HDU1520 Anniversary party(树形DP)

Anniversary party

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)
Total Submission(s): 16631    Accepted Submission(s): 6326


 

Problem Description

There is going to be a party to celebrate the 80-th Anniversary of the Ural State University. The University has a hierarchical structure of employees. It means that the supervisor relation forms a tree rooted at the rector V. E. Tretyakov. In order to make the party funny for every one, the rector does not want both an employee and his or her immediate supervisor to be present. The personnel office has evaluated conviviality of each employee, so everyone has some number (rating) attached to him or her. Your task is to make a list of guests with the maximal possible sum of guests' conviviality ratings.

 

 

Input

Employees are numbered from 1 to N. A first line of input contains a number N. 1 <= N <= 6 000. Each of the subsequent N lines contains the conviviality rating of the corresponding employee. Conviviality rating is an integer number in a range from -128 to 127. After that go T lines that describe a supervisor relation tree. Each line of the tree specification has the form: 
L K 
It means that the K-th employee is an immediate supervisor of the L-th employee. Input is ended with the line 
0 0

 

 

Output

Output should contain the maximal sum of guests' ratings.

 

 

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

 

 

Source

Ural State University Internal Contest October'2000 Students Session

 

 

Recommend

linle

 很基础的树形DP入门题啦。题目大意就是每个人都有一个欢乐值,在有直属关系的同事不能选的前提下,请问能达到的最大欢乐值之和。也就是所谓的求最大独立集。

作为刚接触树形DP的萌新,第一想法是:从叶子节点向上,通过这个两个转移方程

dp[fa][0]+=max(dp[x][0],dp[x][1]);//不取自身

dp[fa][1]+=dp[x][0];//取自身

来得到最大的独立集。用一个队列加上一个set来维护节点,perfect!

代码:

#include<iostream>
#include<cstring>
#include<cstdio>
#include<queue>
#include<set>
using namespace std;
const int size=6005;
int edge[size];
int dp[size][2];
int unleaf[size];
int v[size];
queue<int> point;
set<int> s;
int main()
{
	int n;
	while(cin>>n)
	{
		while(!point.empty()) point.pop();
		s.clear();
		memset(dp,0,sizeof(dp));
		memset(unleaf,0,sizeof(unleaf));
		memset(edge,0,sizeof(edge));
		int i;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&v[i]);//读入每个人的快乐值 
		}
		int a,b;
		
		while(~scanf("%d%d",&a,&b)&&a)
		{
			edge[a]=b;//a的父节点是b 
			unleaf[b]=1;//假如他有过作父节点的经历,则一定不是叶子节点 
		}
		for(i=1;i<=n;i++)
		{
			if(!unleaf[i])
			{
				point.push(i);//把所有的叶子节点入队 
			}
			dp[i][1]=v[i];
			dp[i][0]=0;
		}
		int maxn=0;
		//从叶子节点向根节点dp 
		while(!point.empty())
		{
			while(!point.empty())
			{
				int x=point.front();
				point.pop();
				int fa=edge[x];
				dp[fa][0]+=max(dp[x][0],dp[x][1]);//不取自身 
				dp[fa][1]+=dp[x][0];//取自身 
				if(fa) s.insert(fa);//去重 
			}
			for(auto It=s.begin();It!=s.end();It++)
			{
				int temp=*It;
				maxn=max(dp[temp][0],maxn);
				maxn=max(dp[temp][1],maxn);
				point.push(temp);
			}
			s.clear();
		} 
		cout<<maxn<<endl;
	}
	return 0;
}

编译,样例通过,提交。

WA了。。。。。。

到底是怎么回事呢?我们来看下面这幅图:

不难发现,按照我的一层一层向上更新的办法更新到根节点时,x节点尚未更新,因此左节点的内容就没有加上来,自然就错了。可以看出我一开始的想法只适用于完美叉树。

因此我们需要修改自己的想法,从根节点向下进行搜索,再利用递归的原理求出子节点的值。正确代码如下:

#include<iostream>
#include<cstdio>
#include<vector>
#include<cstring>
using namespace std;
const int size=6005;
int edge[size];
int dp[size][2];
int unroot[size];
int v[size];
vector<int> son[size];
int flag[size];
void dfs(int node)
{
	flag[node]=1;
	for(int i=0;i<son[node].size();i++)
	{
		dfs(son[node][i]);
		int s=son[node][i];
		dp[node][0]+=max(dp[s][0],dp[s][1]);
		dp[node][1]+=dp[s][0];
	} 
}
int main()
{
	int n;
	while(cin>>n)
	{
		memset(dp,0,sizeof(dp));
		memset(unroot,0,sizeof(unroot));
		memset(edge,0,sizeof(edge));
		memset(flag,0,sizeof(flag));
		int i;
		for(i=1;i<=n;i++)
		{
			scanf("%d",&v[i]);//读入每个人的快乐值 
			son[i].clear();
		}
		int a,b;
		
		while(~scanf("%d%d",&a,&b)&&a)
		{
			son[b].push_back(a);//a的父节点是b 
			unroot[a]=1;//假如他有过作子节点的经历,则一定不是根节点 
		}
		int root;
		for(i=1;i<=n;i++)
		{
			if(!unroot[i])
			{
				root=i;
			}
			dp[i][1]=v[i];
			dp[i][0]=0;
		}
		dfs(root);
		int maxn=max(dp[root][0],dp[root][1]);
		cout<<maxn<<endl;
	}
	return 0;
}

 

posted @ 2018-08-03 21:50  Fly_White  阅读(127)  评论(0编辑  收藏  举报