p280 9.4.2
原问题d(i)是以i为根节点,子问题是以i的儿子节点和以i的孙子节点为根节点。
讲解中的“当计算出一个d(i)后,用它去更新i的父亲和祖父节点的累加值”,对应到代码,需要从树的叶子节点开始计算d(i),可以用dfs
下面是 poj 2342的代码,例题9-13 UVa 1220 对应 poj 3342
#define _CRT_SECURE_NO_WARNINGS #include<cstdio> #include<cstdlib> #include<cmath> #include<cstring> #include<vector> #include<algorithm> using namespace std; int N;// 1 <= N <= 6000; const int maxn = 6000; // d[u][0]表示当不选前节点u,能获得的最大conviviality rating // d[u][1]表示当选择前结点u,能获得的最大conviviality rating int d[maxn + 5][2]; int visit[maxn + 5][2]; // d[u][k] already calculated // the supervisor relation forms a tree int parent[maxn + 5]; int root; vector<int> sons[maxn + 5]; // sons of a parent // d[u][k], k==1 or k==0 // depth first search int dp(int u, int k) { if (visit[u][k] > 0) return d[u][k]; if (k == 0) d[u][0] = 0; for (int j = 0; j < sons[u].size(); j++) { // for each son of vertex u int v = sons[u][j]; if (k == 1) { // select u, not select v d[u][1] += dp(v,0); // dfs } else { // not select u, select or not select v d[u][0] += max(dp(v, 1), dp(v, 0)); // dfs } } visit[u][k] = 1; return d[u][k]; } int main() { while (scanf("%d", &N) != EOF){ memset(d, 0, sizeof(d)); memset(visit, 0, sizeof(visit)); memset(parent, 0, sizeof(parent)); for (int i = 1; i <= N; i++) sons[i].clear(); for (int i = 1; i <= N; i++) scanf("%d", &d[i][1]); for (int i = 1; i <= N; i++){ int L, K; scanf("%d%d", &L, &K); if (L == 0 && K == 0) // end of input break; parent[L] = K; sons[K].push_back(L); } for (int i = 1; i <= N; i++){ if (parent[i] == 0){ root = i; break; } } printf("%d\n", max(dp(root, 0), dp(root, 1))); } return 0; }
时间: 2024-11-10 09:47:52