Problem Description
没有上司的舞会
某大学有N个职员,编号为1~N。他们之间有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。现在有个周年庆宴会,宴会每邀请来一个职员都会增加一定的快乐指数Ri,但是呢,如果某个职员的上司来参加舞会了,那么这个职员就无论如何也不肯来参加舞会了。所以,请你编程计算,邀请哪些职员可以使快乐指数最大,求最大的快乐指数。
Analysis of ideas
定义dp[n][2]
dp[i][0]表示第i个人不去,dp[i][1]表示第i个人去
那么转移方程就是(假设j是i的儿子)
假设i不去,j去不去都可以
dp[i][0] += max(dp[j][0],dp[j][1])
假设i去,j就不能去
dp[i][1] += dp[j][0]
树形dp的题目一般是先dfs,回溯的时候进行状态转移
Accepted code
#include <bits/stdc++.h>
using namespace std;
#define mem(a,b) memset(a,b,sizeof(a))
#define cin(a) scanf("%d",&a)
#define pii pair<int,int>
#define ll long long
#define gcd __gcd
const int inf = 0x3f3f3f3f;
const int maxn = 10100;
const int M = 1e9+7;
int n,m,k,t;
int dp[maxn][2]; //1去,0不去
int p[maxn]; //代表i去的快乐程度
int pre[maxn];
vector<int> a[maxn];
void dfs(int s)
{
dp[s][1] = p[s];
for(auto i : a[s])
{
dfs(i);
dp[s][1] += dp[i][0];
dp[s][0] += max(dp[i][1],dp[i][0]);
}
}
int main()
{
cin(n);
for(int i = 1; i <= n; i++)
{
cin(p[i]);
}
int x,y;
while(scanf("%d%d",&x,&y) && x)
{
a[y].push_back(x);
pre[x] = y;
}
int root;
for(int i = 1; i <= n; i++)
{
if(pre[i] == 0)
{
root = i;
break;
}
}
dfs(root);
cout<<max(dp[root][1],dp[root][0])<<endl;
return 0;
}