题目大意: Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。要你求出舞会可以组织出的最大快乐指数。
思路:显然,这是一个树形DP。因为一个根节点选不选会产生不同的情况,所以要开一个二维数组进行记录。记f[i][0]表示以i为根的子树在选择i的情况下能达到的最大快乐值,f[i][1]表示以i为根的子树在不选择i的情况下能达到的最大快乐值,显然状态转移方程有f[i,0]+=max(f[son[i],0],f[son[i],1],f[i,1]=∑f[son[i],0]+value[i]。最后,ans=max(f[root,1],f[root,0])。但根并没有给出,所以需要处理找根。
代码如下:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<vector>
#include<algorithm>
using namespace std;
const int maxn=6005;
int n,c[maxn],f[maxn][2],root;
vector<int> son[maxn];
bool rot[maxn];
void init()
{
scanf("%d",&n);
memset(rot,1,sizeof(rot));
for (int i=1;i<=n;++i)
{
int ci;
scanf("%d",&ci);
c[i]=ci;
}
int l,k;
while (scanf("%d%d",&l,&k)==2)
{
if (l==0 && k==0)
break;
son[k].push_back(l);
rot[l]=0;
}
memset(f,0,sizeof(f));
}
void getroot()
{
for (int i=1;i<=n;++i)
{
if (rot[i])
{
root=i;
return;
}
}
}
void solve(int root)
{
if (son[root].empty())
{
f[root][1]=c[root];
f[root][0]=0;
return;
}
if (f[root][0]!=0 || f[root][1]!=0)
return;
vector<int>::iterator it;
for (it=son[root].begin();it!=son[root].end();++it)
{
solve((*it));
}
for (it=son[root].begin();it!=son[root].end();++it)
f[root][0]+=max(f[(*it)][1],f[(*it)][0]);
for (it=son[root].begin();it!=son[root].end();++it)
f[root][1]+=f[(*it)][0];
f[root][1]+=c[root];
}
int main()
{
init();
getroot();
solve(root);
printf("%d",max(f[root][0],f[root][1]));
}