题意:宴会举办者要邀请一批客人,所有客人之间的关系可以看成一棵树,上层的监督下层的。已知直接相邻层的人不能被同时邀请,而且每个人有个欢乐值。问举办者如何邀请客人能满足上述条件,而且使得欢乐值最大。
思路:树形dp(树上的带权最大独立集问题)。从root开始搜索,dp[i][0]表示在以i为root的子树中不邀请i客人达到的最大欢乐值,dp[i][1]表示在以i为root的子树中邀请i客人达到的最大欢乐值。邀请了i,那么i的所有直接下层节点必然不能邀请,未邀请i,其直接下层节点可请可不请。
#include <stdio.h> #include <string.h> #define N 6005 #define max(a,b) ((a)>(b)?(a):(b)) struct edge{ int y,next; }e[N]; int dp[N][2],s[N],first[N],flag[N]; int n,top; void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } void dfs(int x){ int i,y; dp[x][1] = s[x]; for(i = first[x];i!=-1;i=e[i].next){ y = e[i].y; dfs(y); dp[x][1]+=dp[y][0]; dp[x][0]+=max(dp[y][0],dp[y][1]); } } int main(){ freopen("a.txt","r",stdin); while(scanf("%d",&n)!=EOF){ int i,a,b; memset(dp,0,sizeof(dp)); memset(first,-1,sizeof(first)); memset(flag,0,sizeof(flag)); top = 0; for(i = 1;i<=n;i++) scanf("%d",&s[i]); for(i = 1;i<=n;i++){ scanf("%d %d",&a,&b); if(a){ add(b,a); flag[a] = 1; } } for(i = 1;i<=n;i++) if(!flag[i]) break; dfs(i); printf("%d\n",max(dp[i][0],dp[i][1])); } return 0; }
3342:求一棵树的独立数(不带权),并且要求输出取得独立数的方案是否唯一。
方法仍然是树形dp没什么好说,是否唯一也是开一个数组记录即可。子树如果都是唯一的,那么当前也是唯一的;如果子树中有一个不唯一,那么当前不唯一。
#include <cstdio> #include <string> #include <cstdlib> #include <cmath> #include <algorithm> #include <map> using namespace std; #define INF 0x3fffffff #define clr(s,t) memset(s,t,sizeof(s)) #define N 205 map<string,int> mm; int n; struct edge{ int y,next; }e[N<<1]; int first[N],top,dp[N][2],flag[N][2]; char s[105],t[105]; void add(int x,int y){ e[top].y = y; e[top].next = first[x]; first[x] = top++; } void dfs(int x,int fa){ dp[x][1] = 1; dp[x][0] = 0; for(int i = first[x];i!=-1;i=e[i].next){ int y = e[i].y; if(y != fa){ dfs(y,x); dp[x][1] += dp[y][0]; if(flag[y][0]) flag[x][1] = 1; dp[x][0] += max(dp[y][1],dp[y][0]); if(dp[y][1]==dp[y][0] || (dp[y][1]<dp[y][0]&&flag[y][0]) || (dp[y][1]>dp[y][0]&&flag[y][1])) flag[x][0] = 1; } } } int main(){ while(scanf("%d",&n) && n){ int i,len = 0; clr(first, -1); clr(flag, 0); top = 0; mm.clear(); scanf("%s",s); mm[s] = ++len; for(i = 1;i<n;i++){ scanf("%s %s",s,t); if(!mm.count(s)) mm[s] = (++len); if(!mm.count(t)) mm[t] = (++len); add(mm[s],mm[t]); add(mm[t],mm[s]); } dfs(1,0); if(dp[1][0]<dp[1][1]){ printf("%d ",dp[1][1]); if(!flag[1][1]) printf("Yes\n"); else printf("No\n"); }else if(dp[1][0] == dp[1][1]){ printf("%d No\n",dp[1][0]); }else{ printf("%d ",dp[1][0]); if(!flag[1][0]) printf("Yes\n"); else printf("No\n"); } } return 0; }