没有上司的舞会 洛谷P1352
Description
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
Input
第一行一个整数N。接下来N行,第i+1行表示i号职员的快乐指数Ri。接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
Output
输出最大的快乐指数。
Hint
-128<=Ri<=127,1<=N<=6000
Solution
用邻接表存树,找到根结点,重点是两个状态转移方程:
当root结点是选了的时候:
r[root][1]=r[i][0]+r[root][1];
当root结点没选的时候:
r[root][0]=max(r[i][1]+r[root][0],r[root][0]+r[i][0]);
最后取选root和不选root的最大值就行了。
注意事项:
1.状态转移外面套邻接表的循环,并且要递归地转移。
2.Max里面就不要用max了容易卡着,?:挺好用的。
3.关于状态转移方程,他没选的时候就是他自己加上他的儿子选了或者没选的最大值,他选了就是他自己加上他儿子没选。
luoguAC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 50005
using namespace std;
int r[maxn][2],first[2*maxn+5],nextt[maxn*2+5],rd[maxn];
int n,x,y,root;
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&r[i][1]);
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
rd[x]++;
nextt[x]=first[y];
first[y]=x;
}
for(int i=1;i<=n;i++){
if(!rd[i]){
root=i;
break;
}
}
}
int Max(int x,int y,int z){
int t=x>y?x:y;
return t>z?t:z;
}
int MMax(int x,int y,int z,int w){
int t=x>y?x:y;
int o=z>w?z:w;
return t>o?t:o;
}
void workk(int root){
for(int i=first[root];i;i=nextt[i]){
workk(i);
r[root][1]=Max(r[root][1],r[i][0]+r[root][1],r[i][0]);
r[root][0]=MMax(r[root][0],r[i][1]+r[root][0],r[i][1],r[i][0]);
}
}
int main(){
init();
workk(root);
printf("%d\n",max(r[root][1],r[root][0]));
return 0;
}
CQYZoj上AC代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#define maxn 50005
using namespace std;
int r[maxn][2],first[2*maxn+5],nextt[maxn*2+5],rd[maxn];
int n,x,y,root;
void init(){
scanf("%d",&n);
for(int i=1;i<=n;i++){
scanf("%d",&r[i][1]);
}
for(int i=1;i<=n-1;i++){
scanf("%d%d",&x,&y);
rd[x]++;
nextt[x]=first[y];
first[y]=x;
}
for(int i=1;i<=n;i++){
if(!rd[i]){
root=i;
break;
}
}
}
void workk(int root){
for(int i=first[root];i;i=nextt[i]){
workk(i);
r[root][1]=r[i][0]+r[root][1];
r[root][0]=max(r[i][1]+r[root][0],r[root][0]+r[i][0]);
}
}
int main(){
init();
workk(root);
printf("%d\n",max(r[root][1],r[root][0]));
return 0;
}