没有上司的舞会 洛谷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;
}
posted @ 2018-11-30 17:09  虚拟北方virtual_north。  阅读(116)  评论(0编辑  收藏  举报