Description
有个公司要举行一场晚会。
为了能玩得开心,公司领导决定:如果邀请了某个人,那么一定不会邀请他的上司
(上司的上司,上司的上司的上司……都可以邀请)。
每个参加晚会的人都能为晚会增添一些气氛,求一个邀请方案,使气氛值的和最大。
Input
第1行一个整数N(1<=N<=6000)表示公司的人数。
接下来N行每行一个整数。第i行的数表示第i个人的气氛值x(-128<=x<=127)。
接下来每行两个整数L,K。表示第K个人是第L个人的上司。
输入以0 0结束。
Output
一个数,最大的气氛值和。
Sample Input
7
1
1
1
1
1
1
1
1 3
2 3
6 4
7 4
4 5
3 5
0 0
Sample Output
5
题目大意:
给你一棵有n个节点的树,每个节点上都有一个值,现要求在每一对子节点和父节点不同时选的情况下这棵树最大值。
题解
其实我们可以从一个子节点来推出父节点,一个节点无非两种状态,选或不选,那么我们就可以从这两种状态着手。
选:初始值为这个节点的值,并且我们只能以当前值累加每一个子节点在不选的情况下的值。
不选:初始值为0,接着以当前节点最大值为每一个子节点选和不选这两种情况的最大值累加上当前值。
题目的答案为根节点选或不选两者之间的最大值。
代码实现如下:
#include <bits/stdc++.h>
using namespace std;
int sum,n,s;
int pre[100001],now[100001],son[100001],v[100001],m[20001];
bool pp[50001];
int f[100000][3];//此数组代表当前值的两种情况:0为不选,1为选
void tot(int a,int b) {
pre[++sum]=now[a];
now[a]=sum;
son[sum]=b;
}//还原这棵树
void dfs(int u) {
pp[u]=1;
for(int i=now[u]; i; i=pre[i]) {
int k=son[i];
if(!pp[k]) {
dfs(k);
f[u][1]+=f[k][0];//选的情况
f[u][0]+=max(f[k][0],f[k][1]);//不选的情况
}
}
f[u][1]+=v[u];//再此节点加上选的情况的值
}
int main() {
int a,b,ans;
scanf("%d",&n);
for(int i=1; i<=n; i++)
scanf("%d",&v[i]);
while(1) {
scanf("%d%d",&a,&b);
if(a==0&&b==0)
break;
tot(b,a);
m[a]++;
}
for(int i=1; i<=n; i++)
if(m[i]==0) {
s=i;//找出根节点
break;
}
dfs(s);
cout<<max(f[s][1],f[s][0])<<endl;//得出答案
return 0;
}
第七篇优快云,有不当之处请见谅