1. 程式人生 > >Anniversary party (第一道樹狀dp)

Anniversary party (第一道樹狀dp)

 

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

 

題意:在一個有根樹上每個節點有一個權值,每相鄰的父親和孩子只能選擇一個,問怎麼選擇總權值之和最大。

思路:

樹形dp的常規入門題:設dp[i][0]表示:當前這個點不選,dp[i][1]表示當前這個點選擇的最優解。

轉移方程:dp[cur][0]+=max(dp[son][1],dp[son][0]);//當前這個點不選,那他的孩子可選可不選,取 
最大的。 
dp[cur][1]+=dp[son][0]//當前這點選擇,那他的孩子就不能選擇。
 

唯一個問題是我一開始用陣列存樹,就是f[b]=a表示b的父親是a ,然後尋找兒子的時候就從頭到尾遍歷On, 總是TLE,,,,氣得我,又去網上看了別人用得vector,遂ac

另外,為什麼這個hdu的題意中看不出是多case題啊,,,無語遼。。

AC程式碼:

#include<iostream>
#include<cstring>
#include<vector> 
using namespace std;
vector<int> e[6005];
int n;
int dp[6005][3],flag[6005];
void dfs(int root)
{
	for(int i=0;i<e[root].size();i++) //dfs它的所有孩子 
	{
		int son=e[root][i];
		dfs(son);
		dp[root][1]+=dp[son][0];
		dp[root][0]+=max(dp[son][0],dp[son][1]);
	}
}
int main()
{
	int l,k,i;
	int root;
	while(scanf("%d",&n)!=EOF)
	{
	memset(flag,0,sizeof(flag));
	for(i=1;i<=n;i++)
	{
	scanf("%d",&dp[i][1]);
	dp[i][0]=0;
	e[i].clear();
	}
	while(~scanf("%d%d",&l,&k)&&l&&k)
	{
		e[k].push_back(l); //l加入k的子節點的容器 
		flag[l]=1;       //標記為有子節點的元素 
	}
	for(i=1;i<=n;i++)
	{
		if(flag[i]==0) //找到根節點(沒有子節點) 
		{
			root=i;
			break;
		}
	}
	dfs(root);
	int maxx=0;
	printf("%d\n",max(dp[root][1],dp[root][0]));
	}
	return 0;
}