Anniversary party
题意:你要举行一个晚会,所有人的关系可以构成一棵树,要求上下级关系的人不能同时出现,每一个人都有一个rating值,要求使整个晚会的rating值最大。
/* 解题思路:树形dp,随意从一个点开始扩展,把周围所有节点的dp都解决出来,然后加上去即可。 用dp[i][0]表示不选中i号,周围的都可以选的最大值,dp[i][1]表示选中i号,那么周围都不能选的最大值。 则 dp[i][0]+=(dp[j][1],dp[j][0]) dp[i][1]+=dp[j][0] i和j相邻,并且在求i的时候从j扩展的都已经求出来。 */ #include<cstdio> #include<iostream> #include<vector> #include<string.h> using namespace std; #define Max(a,b) a>b?a:b vector<int> q[6005]; int visit[6005],rating[6005],dp[6005][6005]; void dfs(int r) { //printf("r=%d ",r); int i,v; visit[r]=1; if(q[r].size()==0) { dp[r][1]=rating[r]; dp[r][0]=0; } int dp1=0,dp0=0; for(i=0;i<q[r].size();i++) { v=q[r][i]; if(!visit[v]) { //printf("v=%d ",v); dfs(v); } dp1+=dp[v][0];//若选了此节点,则孩子都不能选 dp0+=Max(dp[v][0],dp[v][1]);//若不选此节点,则孩子可选可不选 } dp[r][1]=dp1+rating[r]; dp[r][0]=dp0; } int main() { int n,root; int i,j,k; while(~scanf("%d",&n)) { for(i=1;i<=n;i++) q[i].clear(); for(i=1;i<=n;i++) scanf("%d",&rating[i]); memset(visit,0,sizeof(visit)); int c,f; root=1; while(scanf("%d%d",&c,&f),c||f) { if(c==root) root=f;//新学习的一个寻根的小技巧 q[f].push_back(c); } dfs(root); printf("%d ",Max(dp[root][1],dp[root][0])); } return 0; }