【树形dp】SGU 195 New Year Bonus Grant
题意:
给出一棵树,根节点是1,要求根据以下要求选择最多的节点:
①不能选择1
②若选择当前节点,那么该节点的父节点和儿子都不能选择。
③若某节点的某一个儿子节点被选择,那么该节点的其他儿子不能被选择
样例分析图:
思路:用dp[u][2]表示u节点是否被选择的最大值,则dp[u][1]=sum{dp[v][0]}+1,dp[u][0]=max(sum{dp[v][0]} , sum{dp[v][0]}-min{dp[v][0]+dp[v][1]});
代码:
#include<cstdio> #include<cstring> #include <algorithm> using namespace std; typedef long long ll; const int inf = 0x3f3f3f3f; const int maxn=500000+10; struct Edge { int v,next; }edges[maxn]; int head[maxn],dp[maxn][2],flag[maxn],nEdge; int ans[maxn],cnt; void AddEdge(int u,int v) { nEdge++; edges[nEdge].v=v; edges[nEdge].next=head[u]; head[u]=nEdge; } void dfs(int u) { dp[u][0]=0;dp[u][1]=1; int sum=0,tmp=inf; for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].v; dfs(v); dp[u][1]+=dp[v][0]; sum+=dp[v][0]; if(dp[v][0]-dp[v][1]<tmp) { tmp=dp[v][0]-dp[v][1]; flag[u]=v; } } dp[u][0]=max(sum,sum-tmp); } void dfs2(int u,int s) { for(int k=head[u];k!=-1;k=edges[k].next) { int v=edges[k].v; if(s==1) dfs2(v,0); else { if(flag[u]!=v) dfs2(v,0); else { ans[cnt++]=v; dfs2(v,1); } } } } int main() { int n; scanf("%d",&n); memset(head,0xff,sizeof(head)); nEdge=-1; int v; for(int i=2;i<=n;++i) { scanf("%d",&v); AddEdge(v,i); } dfs(1); printf("%d\n",dp[1][0]*1000); cnt=0; dfs2(1,0); sort(ans,ans+cnt); for(int i=0;i<cnt;++i) { if(i) printf(" "); printf("%d",ans[i]); } printf("\n"); return 0; }