POJ 2342 Anniversary party(树形DP)

题目来源:http://poj.org/problem?id=2342

Anniversary party

Time Limit: 1000MS

Memory Limit: 65536K

Total Submissions: 10684

Accepted: 6121

Description

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

Input

Employees are numbered from 1 to N. A first lineof input contains a number N. 1 <= N <= 6 000. Each of the subsequent Nlines contains the conviviality rating of the corresponding employee.Conviviality rating is an integer number in a range from -128 to 127. Afterthat go N – 1 lines that describe a supervisor relation tree. Each line of thetree specification has the form: 
L K 
It means that the K-th employee is an immediate supervisor of the L-themployee. 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

SampleOutput

5

Source

Ural State University InternalContest October'2000 Students Session

 -----------------------------------------------------

思路

题意:在一棵节点带权的树中选择若干的节点,满足如果一个节点被选中,则它的父节点不能同时被选中。存在一种选择方案,使得选中的节点权值之和最大,求该最大权值。

算法:树形dp

dp[u][0]: 以节点u为根的子树的不取节点u的权

dp[u][1]: 以节点u为根的子树的取节点u的权

dp[u][0] = sum_v(max(dp[v][0], dp[v][1])

dp[u][1] = sum_v(dp[v][0]) + weight[u]              

其中vu的子节点

具体实现采用递归,从根节点开始递归

-----------------------------------------------------

代码 

//树形dp
//dp[u][0]: 以节点u为根的子树的不取节点u的权; dp[u][1]: 以节点u为根的子树的取节点u的权
// dp[u][0] = sum_v(max(dp[v][0], dp[v][1])
// dp[u][1] = sum_v(dp[v][0]) + weight[u]			其中v是u的子节点

#include<iostream>
#include<fstream>
#include<vector>
using namespace std;

const int NMAX = 6005;
int rat[NMAX] = {};						// 节点的权
vector<int> son[NMAX] = {};				// 节点的子节点集
int dp[NMAX][2] = {};					// 树形dp[u][0]: 以节点u为根的子树的不取节点u的权; dp[u][1]: 以节点u为根的子树的取节点u的权
bool vis[NMAX] = {};					// 是否是某个节点的子节点(用于找根节点)

void dfs(int u)
{
	int i= 0, v;
	dp[u][0] = 0;						// dp[u][0]不取u自己的权
	dp[u][1] = rat[u];					// dp[u][1]要取u自己的权
	if (son[u].size() > 0)				// 如果u不是叶子节点
	{
		for (i=0; i<son[u].size(); i++)
		{
			v = son[u].at(i);			// v是u的一个子节点
			dfs(v);						// 递归求解以v为根的子树的权
			dp[u][0] += max(dp[v][1], dp[v][0]);	// 不取u, 则v取不取都可以
			dp[u][1] += dp[v][0];		// 取u, 则只能不取v
		}
	}
}

int main()
{
#ifndef ONLINE_JUDGE
	ifstream fin ("2342.txt");
	int n,i,u,v,root;
	fin >> n;
	for (i=0; i<n; i++)
	{
		fin >> rat[i];
	}
	while (fin >> v >> u)
	{
		if (u==0 &&v==0)
		{
			break;
		}
		son[--u].push_back(--v);
		vis[v] = 1;
	}
	fin.close();
	for (i=0; i<n; i++)							// 不是任何节点的子节点的节点就是根节点
	{
		if (!vis[i])
		{
			root = i;
			break;
		}
	}
	dfs(root);									// 从根节点开始递归
	cout << max(dp[root][0], dp[root][1]);		// 输出根节点dp的较大者
	return 0;
#endif
#ifdef ONLINE_JUDGE
	int n,i,u,v,root;
	cin >> n;
	for (i=0; i<n; i++)
	{
		cin >> rat[i];
	}
	while (cin >> v >> u)
	{
		if (u==0 &&v==0)
		{
			break;
		}
		son[--u].push_back(--v);
		vis[v] = 1;
	}
	for (i=0; i<n; i++)							// 不是任何节点的子节点的节点就是根节点
	{
		if (!vis[i])
		{
			root = i;
			break;
		}
	}
	dfs(root);									// 从根节点开始递归
	cout << max(dp[root][0], dp[root][1]);		// 输出根节点dp的较大者
#endif
}


猜你喜欢

转载自blog.csdn.net/da_kao_la/article/details/80765635