POJ 3342 (树形DP)
题意 :给出一些上下级关系,要求i和i的直接上级不能同时出现,现在选出一些人构成一个集合,问你这个集合里面的最大人数是都少,同时给出这个最大的人数的集合是否唯一。
思路:树形DP,dp[i][0],表示以i为跟节点的子树,不取i时的最优解,dp[i][1]表示以i为跟节点的子树,取i时的最优解,再另设only数组,only[i][0]表示以i为跟节点的子树,不i时最 优解是否唯一,only[i][1]表示以i为跟节点取i时最优解是否唯一
#include<map> #include<cstdio> #include<string> #include<cstring> #include<iostream> #include<algorithm> #define MAXN 222 using namespace std; typedef struct{ int to, next; }Edge; Edge edge[MAXN]; int dp[MAXN][2], head[MAXN]; int only[MAXN][2], cnt; void addEdge(int u, int v, int k){ edge[k].to = v; edge[k].next = head[u]; head[u] = k; } void dfs(int s){ dp[s][0] = 0; dp[s][1] = 1; for(int i = head[s];~i;i = edge[i].next){ int u = edge[i].to; dfs(u); if(dp[u][0] > dp[u][1]){ dp[s][0] += dp[u][0]; if(only[u][0]) only[s][0] = 1; }else if(dp[u][0] < dp[u][1]){ dp[s][0] += dp[u][1]; if(only[u][1]) only[s][0] = 1; }else{ dp[s][0] += dp[u][0]; only[s][0] = 1; } dp[s][1] += dp[u][0]; if(only[u][0]) only[s][1] = 1; } } int main(){ int n, k; string s1, s2; map<string, int>mp; // freopen("in.c", "r", stdin); while(~scanf("%d", &n) && n){ mp.clear(), k = 1, cnt = 0; cin >> s1; mp[s1] = k++; memset(head, -1, sizeof(head)); memset(only, 0, sizeof(only)); for(int i = 1;i <= n-1; i++){ cin >> s1 >> s2; if(mp.find(s1) == mp.end()) mp[s1] = k++; if(mp.find(s2) == mp.end()) mp[s2] = k++; addEdge(mp[s2], mp[s1], i); } addEdge(0, 1, n); dfs(0); printf("%d ", max(dp[1][0], dp[1][1])); if(!only[0][0]) printf("Yes\n"); else printf("No\n"); } return 0; }