2019暑假集训 周年纪念晚会
题目描述
Ural 州立大学的校长正在筹备学校的80周年纪念聚会。由于学校的职员有不同的职务级别,可以构成一棵以校长为根的人事关系树。每个资源都有一个唯一的整数编号,从1到N编号,且对应一个参加聚会所获得的欢乐度。为使每个职员都感到快乐,校长设法使每个职员和其直接上司不会同时参加聚会。
你的任务是设计一份参加聚会者的名单,使总欢乐度最高。
你的任务是设计一份参加聚会者的名单,使总欢乐度最高。
输入
第一行是一个整数N;
接下来N行对应N个职员的欢乐度,第i行的一个整数为第i个职员的欢乐度pi;
接着是学校的人事关系树,每一行格式为 L K ,表示第K个职员是第L个职员的直接上司,输入以 0 0 结束。
接下来N行对应N个职员的欢乐度,第i行的一个整数为第i个职员的欢乐度pi;
接着是学校的人事关系树,每一行格式为 L K ,表示第K个职员是第L个职员的直接上司,输入以 0 0 结束。
输出
输出参加聚会者获得的最大欢乐度。
样例输入
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
样例输出
5
由于关系网络呈一棵树 很容易想到树形dp
所以对于每个人我们有去(1)不去(0)两种可能:
(1)第x个人去,则其儿子不可能去,即dp[x][1]+=dp[y][0];
(2)第x个人不去,则其儿子可能去可能不去,两种可能取最小值,则dp[x][0]+=min(dp[y][0],dp[y][1]);
所以上代码
#include<iostream> #include<cstdio> #include<cstring> using namespace std; int n,p[10050],dp[10050][2],head[10050],num,book[10050],root=1; struct edge { int u,v,nxt; }e[200500]; void add(int u,int v) { e[++num].u=u;e[num].v=v; e[num].nxt=head[u],head[u]=num; } void DP(int x,int fa) { for(int st=head[x];st!=-1;st=e[st].nxt) { int y=e[st].v; if(y==fa)continue; DP(y,x); // dp[x][0]=max(dp[x][0],dp[y][1]); // dp[x][1]=max(dp[x][1],dp[y][0]+p[x]); dp[x][0]+=max(dp[y][1],dp[y][0]); dp[x][1]+=dp[y][0]; } dp[x][1]+=p[x]; return; } int main() { memset(head,-1,sizeof head); scanf("%d",&n); for(int i=1;i<=n;i++)scanf("%d",&p[i]); int l=1,k=1; while(!(l==0&&k==0))scanf("%d%d",&l,&k),add(k,l),book[l]=1; while(book[root])root++; DP(root,-1); // putchar('\n'); // putchar('\n'); // for(int i=1;i<=n;i++)printf("%d %d\n",dp[i][0],dp[i][1]); int ans=max(dp[root][0],dp[root][1]); printf("%d",ans); return 0; }
/*====年轻人,瞎搞是出不了省一的,这就是现实====*/