Anniversary party(树形DP入门)
题目链接:https://cn.vjudge.net/contest/317407#problem/A
题目理解:
题意为有n个人要开一个PARTY,编号1到n,每个人都有一个欢乐值,并且每个人都有一个直接上司,为了让气氛更好,要求在这n个人中选一些人去参加PARTY,并且选出的这些人中任意两个人之间都没有直接上司或直接下属关系,求选出人的最大欢乐值。这n个人通过直接上司或直接下属关系构成了一棵树,如果把父节点看做直接上司,那么子节点为下属,而且上司和下属不能同时选择。
题目分析:
定义dp[i][0] 为第i个人不选择所获得的最大欢乐值,dp[i][1] 为第i个人被选择所获得的最大欢乐值;
dp[u][0]表示以u为顶点的子树,不选u点的情况下最大值
dp[u][1]表示以u为顶点的子树,选u点的情况下最大值
那么,
dp[u][0] = sum{ max{dp[v][0], dp[v][1]}, v是u的儿子节点}; //当不选u点时,它的儿子节点可以不选也可以选
dp[u][1] = val[u] + sum{dp[v][0], v是u的儿子节点} //当选了u点时,它的儿子节点必须是不能选
AC代码:
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 #define rep(i,first,last) for(int i=first;i<=last;i++) 5 #define dep(i,first,last) for(int i=first;i>=last;i--) 6 const int maxn=6005; 7 int dp[maxn][2],n; 8 vector<int>son[maxn]; 9 bool vis[maxn]; 10 11 void dfs(int root){ 12 vis[root]=1; 13 rep(i,0,son[root].size()-1){ 14 int v=son[root][i]; 15 if(!vis[v]){ 16 dfs(v); 17 dp[root][1]+=dp[v][0]; 18 dp[root][0]+=max(dp[v][0],dp[v][1]); 19 } 20 } 21 } 22 23 int main() 24 { 25 while(~scanf("%d",&n)){ 26 rep(i,0,n) son[i].clear(); 27 memset(vis,0,sizeof(vis)); 28 rep(i,1,n){ 29 scanf("%d",&dp[i][1]); 30 dp[i][0]=0; 31 } 32 int fa,so; 33 while(scanf("%d%d",&so,&fa)&&(so||fa)){ 34 son[fa].push_back(so); 35 son[so].push_back(fa); 36 } 37 dfs(1); 38 printf("%d\n",max(dp[1][0],dp[1][1])); 39 } 40 return 0; 41 }
1 #include <bits/stdc++.h> 2 using namespace std; 3 typedef long long ll; 4 const int maxn = 6005<<1; 5 const int inf=0x3f3f3f3f; 6 #define rep(i,first,last) for(int i=first;i<=last;i++) 7 #define dep(i,first,last) for(int i=first;i>=last;i--) 8 struct edge{int to,nxt;}e[maxn]; 9 int head[maxn],cnt,n,dp[maxn][2],ans,vis[maxn]; 10 void addedge(int u,int v){ 11 e[cnt].to=v; 12 e[cnt].nxt=head[u]; 13 head[u]=cnt++; 14 } 15 void dfs(int root){ 16 vis[root]=1; 17 for(int i=head[root];i!=-1;i=e[i].nxt){ 18 int v=e[i].to; 19 if(!vis[v]){ 20 dfs(v); 21 dp[root][1]+=dp[v][0]; 22 dp[root][0]+=max(dp[v][0],dp[v][1]); 23 } 24 } 25 } 26 int main(){ 27 while(~scanf("%d",&n)){ 28 cnt=0; 29 memset(head,-1,sizeof(head)); 30 memset(vis,0,sizeof(vis)); 31 rep(i,1,n) scanf("%d",&dp[i][1]),dp[i][0]=0; 32 int u,v; 33 while(scanf("%d%d",&u,&v)&&(v+u)){ 34 addedge(u,v); addedge(v,u); 35 } 36 dfs(1); 37 printf("%d\n",max(dp[1][0],dp[1][1])); 38 } 39 return 0; 40 }