HDU 4274 Spy's Work (树形DP)

题意

给定一棵树,给出一些子树的权值关系,问是否矛盾(初始所有结点的下限为1)

思路

设lmin和lmax表示题目给定的限制范围,默认为[1..oo];amin和amax表示实际符合要求的范围。从根节点开始DP,通过子树的amin更新父节点的amin(父节点的amax一定是oo,因为它自身权值任意),判断此时amin和amax与lmin和lmax是否有交集(实际范围),没有则false。

代码

  [cpp] #include <iostream> #include <cstdio> #include <cmath> #include <algorithm> #include <string> #include <cstring> #include <vector> #include <set> #include <stack> #include <queue> #define MID(x,y) ((x+y)/2) #define MEM(a,b) memset(a,b,sizeof(a)) #define REP(i, begin, end) for (int i = begin; i <= end; i ++) using namespace std; const int N = 10005; const int oo = 0x7fffffff; long long lmin[N], lmax[N], amin[N], amax[N]; vector <int> adj[N]; bool dfs(int u){ bool ok = true; for (int i = 0; i < (int)adj[u].size(); i ++){ int v = adj[u][i]; ok = dfs(v); if (ok == false) return false; amin[u] += amin[v]; amax[u] += amax[v]; } amin[u] = max(amin[u], lmin[u]); amax[u] = min(amax[u], lmax[u]); if (amin[u] <= amax[u]) return true; else return false; } int main(){ int n; while(scanf("%d", &n) != EOF){ for (int i = 1; i <= n; i ++){ adj[i].clear(); lmin[i] = 1; lmax[i] = oo; amin[i] = 1; amax[i] = oo; } for (int i = 2; i <= n; i ++){ int tmp; scanf("%d", &tmp); adj[tmp].push_back(i); } int q; scanf("%d", &q); bool res = true; for (int i = 0; i < q; i ++){ int a, b; char c; scanf("%d%*c%c%*c%d", &a, &c, &b); if (c == '='){ if (b <= lmax[a] && b >= lmin[a]) lmin[a] = lmax[a] = b; else res = false; } else if (c == '<'){ lmax[a] = min((long long)(b - 1), lmax[a]); } else if (c == '>'){ lmin[a] = max((long long)(b + 1), lmin[a]); } } if (!res){ puts("Lie"); } else{ for (int i = 1; i <= n; i ++){ if (lmin[i] > lmax[i]){ res = false; break; } } if (!res){ puts("Lie"); } else{ res = dfs(1); if (res){ puts("True"); } else{ puts("Lie"); } } } } return 0; } [/cpp]  

你可能感兴趣的:(HDU)