HDU - 1520 Anniversary party (树形DP)

题目链接

题目:某公司80年庆典宴会,给出一个n(n个员工),然后n行w[i],表示每个员工的受欢迎值,随后每行给出一个u,v(表示u是v的上司),直到u=v=0.要求出席员工的最大受欢迎值,且员工和其上司不能同时出现.

题解:很明显是一道树形dp,父子结点不能同时选的贪心问题,那么我们只需要用sta标记2种状态,当sta==1时表示父结点选了,子结点不能选,当sta==0时子结点可选可不选,树形dp问题在dfs中dp可以方便很多~

代码如下:

#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define inf 0x3f3f3f3f
#define ll long long
const int maxn = 1e5 + 500;
int w[maxn];//权值
int dp[maxn][2];
bool vis[maxn][2];
vector<int>e[maxn];
int dfs(int pos, int sta, int prt)//pos->当前点,sta->状态,prt->父结点
{
	if (vis[pos][sta]) return dp[pos][sta];
	dp[pos][sta] = 0;
	int ww = 0;  //ww存子树dp得到的最大值
	for (int i = 0; i < e[pos].size(); i++)
	{
		if (e[pos][i] == prt)continue;
		ww += dfs(e[pos][i], 0, pos);
	}
	dp[pos][sta] = max(dp[pos][sta], ww);
	if (sta != 1)
	{
		ww = 0;
		for (int i = 0; i < e[pos].size(); i++)
		{
			if (e[pos][i] == prt)continue;
			ww += dfs(e[pos][i], 1, pos);
		}
		dp[pos][sta] = max(dp[pos][sta], ww + w[pos]);
	}
	vis[pos][sta] = true;
	return dp[pos][sta];
}
int main()
{
	int n;
	while (~scanf("%d", &n))
	{
		memset(vis, 0, sizeof(vis));
		for (int i = 1; i <= n; i++)
			e[i].clear();
		for (int i = 1; i <= n; i++)
			scanf("%d", &w[i]);
		int u, v;
		while (~scanf("%d%d", &u, &v) && u)
		{
			e[u].push_back(v);
			e[v].push_back(u);
		}
		printf("%d\n", dfs(1, 0, -1));
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/weixin_41156591/article/details/81810717