9-13 树的最大独立集
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; }
例题 9-13 对应 poj 3342
#define _CRT_SECURE_NO_WARNINGS #include <cstdio> #include <cstdlib> #include <iostream> #include <cstring> #include <string> #include <vector> #include <map> #include <algorithm> using namespace std; int n;// 1 <= n <= 200; const int maxn = 200; int cnt; // 节点的编号,从1开始 // d[u][0]表示当不选前节点u,能获得的最大个数 // d[u][1]表示当选择前结点u,能获得的最大个数 int d[maxn + 5][2]; int visit[maxn + 5][2]; // d[u][k] & f[u][k] already calculated // f[u][0]表示当不选前节点u,是否唯一 // f[u][1]表示当选择前结点u,是否唯一 int f[maxn + 5][2]; int root; vector<int> sons[maxn + 5]; // sons of a parent map<string, int> dict; // name string --> vertex id int nameToId(const string& str) { if (dict.count(str) == 0){ // not exist dict[str] = cnt++; } return dict[str]; } // compute d[u][k] & f[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]; d[u][k] = k; f[u][k] = 1; 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 if (f[v][0] == 0) // if for any son v it's f[v][0] == 0 then f[u][1] == 0 f[u][1] = 0; } else { // k == 0, not select u, select or not select v d[u][0] += max(dp(v, 1), dp(v, 0)); // dfs if (d[v][0] == d[v][1]) f[u][k] = 0; else if (d[v][0] > d[v][1] && f[v][0] == 0) // select d[v][0] f[u][k] = 0; else if (d[v][1] > d[v][0] && f[v][1] == 0) // select d[v][1] f[u][k] = 0; } } visit[u][k] = 1; return d[u][k]; } int main() { while (scanf("%d", &n) != EOF && n){ memset(d, 0, sizeof(d)); memset(f, 0, sizeof(f)); memset(visit, 0, sizeof(visit)); for (int i = 1; i <= n; i++) sons[i].clear(); cnt = 1; dict.clear(); for (int i = 1; i <= n; i++){ string s1, s2; int son, par; if (i == 1){ cin >> s1; root = nameToId(s1); } else { cin >> s1 >> s2; son = nameToId(s1); par = nameToId(s2); sons[par].push_back(son); } } printf("%d ", max(dp(root, 0), dp(root, 1))); bool unique = false; if (d[root][0] > d[root][1] && f[root][0]) unique = true; if (d[root][1] > d[root][0] && f[root][1]) unique = true; if (unique) printf("Yes\n"); else printf("No\n"); } return 0; }