题目:某公司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;
}