Time Limit: 2000/1000 MS (Java/Others) Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 2668 Accepted Submission(s): 1192
这道题可以简单的描述为有一些数据之间有父子关系,现在需要选择一些数据出来,使数据总的和最大,但要求数据两两之间不能有直接的父子关系。若设节点i为某一个根,则可以设dp[i][0]表示不包括i的子树的最大和,dp[i][1]表示包括节点i的子树的最大和。则最终所求的结果为:
ans=max{dp[i][0],dp[i][1]}
dp[i][0]=sum(max{dp[j][0],dp[j][1]}) //如果不包括i,则其子树的最大和是不包括其孩子 //或者包括其孩子两种可能下的最大和
dp[i][1]=sum(dp[j][0]) //如果包括i,则只能是不包括其孩子的最大和
#include<iostream> #include<cstdio> #include<cstring> using namespace std; const int VM=6010; struct Edge{ int to,nxt; }edge[VM<<1]; int cnt,head[VM]; int n,vis[VM],dp[VM][2],happy[VM]; void addedge(int cu,int cv){ edge[cnt].to=cv; edge[cnt].nxt=head[cu]; head[cu]=cnt++; } void DFS(int u){ if(vis[u]) return ; vis[u]=1; dp[u][1]=happy[u]; for(int i=head[u];i!=-1;i=edge[i].nxt){ int v=edge[i].to; if(!vis[v]){ DFS(v); dp[u][0]+=max(dp[v][0],dp[v][1]); dp[u][1]+=dp[v][0]; } } } int main(){ //freopen("input.txt","r",stdin); while(~scanf("%d",&n)){ cnt=0; memset(head,-1,sizeof(head)); for(int i=1;i<=n;i++) scanf("%d",&happy[i]); int u,v; while(~scanf("%d%d",&u,&v)){ if(u==0 && v==0) break; addedge(u,v); addedge(v,u); } memset(vis,0,sizeof(vis)); memset(dp,0,sizeof(dp)); DFS(1); printf("%d\n",max(dp[1][0],dp[1][1])); } return 0; }