HDU 1520 Anniversary party 树状dp

HDU 1520 Anniversary party 树状dp

题意

大体意思说,一个大学要开一个party,大学里会有很多人回去参加,但是并不是很多人都愿意去,因为有可能遇到自己的直接上司。本来是一个放松的场所,遇到自己的直接boss可真的不大放得开,遇到上上级boss还可以,这就给组织这个活动的部门一个难题,每个人都有自己的开心值,我们该怎么做才能既避免这种尴尬,又能使得参加人的开心值总和最大呢?

先给一个n表示大学里面人的个数,编号从1开始,然后是n个值,表示每个人的开心值,接下来是若干个关系,如1 3表示第三号是第一号的直接boss,当输入0 0的时候表示结束。

这里是保证关系是一个树,而不会有若干个树。

解题思路

显然这是个求解最优的题目,我们可以使用动态规划来进行解决,因为这个关系是一个树状的,所以也就称为树状dp了。

这里我们先定义一个状态,dp[i][0]表示在第i号员工不参加的情况下,以他为根节点的树的最大值,同样的,dp[i][1]就表示在第i号员工参加的情况下,以他为根节点树的最大值。

对于初始化,dp[i][0]=0, dp[i][1]=他参加的开心值

递推关系,这里dp[i][1]={dp[son1][0]+dp[son2][0]+... 。son1,son2等表示i的直接孩子编号}就是一个父节点参加,那么以他为根节点的树的最优值,就是以他的各个孩子节点(不参加时)为根节点树的最优值的和(这里满足最优子结构性质)。

dp[i][0] += max(dp[son][1], dp[son][0]),要对i的每个孩子节点进行判断

代码实现

#include<cmath>
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<iostream>
#include<string>
#include<stack>
#include<queue>
#include<map>
#include<set>
#include<sstream>
typedef long long ll;
using namespace std;
const double esp=1e-6;
const int inf=0x3f3f3f3f;
const int MAXN=6e3+7;
int fa[MAXN], dp[MAXN][2];
vector<int> tre[MAXN];
bool vis[MAXN];
int n;
void dfs(int rt)
{
	for(int i=0; i<tre[rt].size(); i++)
		dfs(tre[rt][i]);
	for(int i=0; i<tre[rt].size(); i++)
	{
		dp[rt][1] += dp[tre[rt][i]][0];
		dp[rt][0] += max(dp[tre[rt][i]][0], dp[tre[rt][i]][1]);
	}
}
int main()
{
	while(cin>>n)
	{
		for(int i=1; i<=n; i++){
			cin>>dp[i][1];
			vis[i] = false;
			fa[i] = i;
			dp[i][0] = 0;
			tre[i].clear();
		}
		int a, b;
		while(cin>>a>>b){
			if(a == 0 && b == 0)
				break;
			fa[a] = b;
			tre[b].push_back(a);
		}
		int root;
		for(int i=1; i<=n; i++)
			if(fa[i] == i){
				root = i;
				break;
			}
		dfs(root);
		cout<<max(dp[root][1], dp[root][0])<<endl;
	}
	return 0;
}
posted @ 2020-03-27 14:55  ALKING1001  阅读(160)  评论(0编辑  收藏  举报