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;
}

 

posted @ 2011-11-30 19:18  枕边梦  阅读(213)  评论(0编辑  收藏  举报