题目大意
poj英文原题&样例(周年聚会)
网页翻译器
大家自己看。
分析
这个题真的跟没有上司的晚会一模一样!!只是改了一下题目描述。同样是找到根节点之后开始边递归边DP。
由题意得,父节点(上司)选了,那么所有儿子(下属)都不能选;父节点不选,那么所有儿子可选可不选。我们设
f
[
i
]
[
1
]
f[i][1]
f[i][1]为选了
i
i
i中这个点的最大活跃度,
f
[
i
]
[
0
]
f[i][0]
f[i][0]为不选这个点的最大活跃度。所以动态转移方程:
f
[
i
]
[
1
]
=
f
[
i
]
[
1
]
+
f
[
a
[
i
]
.
y
]
[
0
]
f[i][1]=f[i][1]+f[a[i].y][0]
f[i][1]=f[i][1]+f[a[i].y][0]
f
[
i
]
[
0
]
=
m
a
x
(
f
[
a
[
i
]
.
y
]
[
0
]
,
f
[
a
[
i
]
.
y
]
[
1
]
)
+
f
[
i
]
[
0
]
f[i][0]=max(f[a[i].y][0],f[a[i].y][1])+f[i][0]
f[i][0]=max(f[a[i].y][0],f[a[i].y][1])+f[i][0]
上代码
#include<iostream>
#include<cstdio>
#include<algorithm>
#include<cstring>
using namespace std;
int n,a[10001],h[10001],f[10001][2],v[10001],tot,m;
struct node
{
int x,y,next;
}e[10001];
void add(int x,int y)
{
//e[++tot]=(node){x,y,h[x]};//邻接表一句顶四句
tot++;
e[tot].x=x;
e[tot].y=y;
e[tot].next=h[x];
h[x]=tot;
}
void dp(int k)
{
f[k][1]=a[k];
for(int i=h[k];i>0;i=e[i].next)
{
dp(e[i].y);
f[k][1]=f[k][1]+f[e[i].y][0];//如果他选,儿子就不选
f[k][0]=max(f[e[i].y][0],f[e[i].y][1])+f[k][0];//他不选,儿子可选可不选
}
}
int main()
{
cin>>n;
for(int i=1;i<=n;i++)
{
cin>>a[i];
}
int x,y;
for(int i=1;i<=n;i++)
{
cin>>x>>y;
if(x==0&&y==0) continue;
add(y,x);
v[x]=1;//证明他不是根节点,x是y的儿子
}
for(int i=1;i<=n;i++)
{
if(v[i]==0)
{
m=i;//找根节点
break;
}
}
dp(m);//从根节点开始DP
cout<<max(f[m][1],f[m][0]);
return 0;
}