hdu1520 Anniversary party(树形dp)
题意:在一棵树上选出一些点,每个点都有一个权值,使得和最大,前提是,父节点和子节点只能选一个。
分析:整个代码与1054基本一样的,就是状态转移方程变了 ,因为题目加了一些限制
dp[i][0]表示以i为根节点的不选i树的最大权值和
dp[i][1]表示以i为根节点的选i的树的最大权值和
状态转移方程:
dp[i][0]+=max(dp[son[i][j]][0],dp[son[i][j]][1]),(0<j<size[i])
dp[i][1]+=dp[son[i][j]][0];(0<j<size[i]) size[i]表示i节点的儿子数
#include<iostream>
#include<algorithm>
#include<vector>
using namespace std;
int v[6001],n,f[6001];
vector<int> son[6001];
int dp[6001][2];
int dfs(int pos,int val)
{
if(dp[pos][val]!=INT_MIN)
return dp[pos][val];
int sum;
if(val==1)
sum=v[pos];
else sum=0;
int size=son[pos].size();
for(int i=0;i<size;i++)
{
if(val==1)
sum+=dfs(son[pos][i],0);
else sum+=max(dfs(son[pos][i],0),dfs(son[pos][i],1));
}
return dp[pos][val]=sum;
}
int main()
{
while(scanf("%d",&n)==1)
{
for(int i=1;i<=n;i++)
{
scanf("%d",&v[i]);
son[i].clear();
f[i]=i;
dp[i][0]=dp[i][1]=INT_MIN;
}
int a,b;
while(scanf("%d %d",&a,&b))
{
if(a==0 && b==0)
break;
son[b].push_back(a);
f[a]=b;
}
int ans;
for(int i=1;i<=n;i++)
{
if(f[i]==i)
{
ans=max(dfs(i,0),dfs(i,1));
break;
}
}
printf("%d\n",ans);
}
return 0;
}

浙公网安备 33010602011771号