【洛谷】P1352 没有上司的舞会
0.总结
Get to the points first. The article comes from LawsonAbs!
树上dp题
- (1)以节点从深到前(子树从小到大)的顺序作为dp的 “阶段”
- (2)dp的状态表示中,第一维通常是节点编号(代表以该节点为根的子树)
- (3)大多数的时候,以递归的形式实现树性动态规划。对于每个节点x,递归的求出其子节点,然后回溯的时候根据转移方程求出根节点x的状态值。
1.题目
2.思路
没什么难点,只要会图的遍历(dfs)+简单dp知识 即可。
- dp[i][0]表示以i为根的树在i不参加的情况下达到的最大快乐值;dp[i][1]表示以i为根的树在i参加的情况下达到的最大快乐值;
- hap[i]表示节点i参会的快乐值
- 状态转移方程很简单。因为笔者太蒟蒻了(不会用
Latex
公式),所以就不给出来了。
3.代码
#include<iostream>
#include<vector>
using namespace std;
const int N = 6005;
int dp[N][2], hap[N],isR[N];//快乐值 ;判断是否是根节点
int n,root;//多少个节点; 根是什么
vector<int> ver[N];//每个节点的子节点序号
void dfs(int cur){
for(int i = 0;i<ver[cur].size();i++){
int y = ver[cur][i];//子树的序号
dfs(y);
dp[cur][0] += max(dp[y][0],dp[y][1]);//cur节点不参加
dp[cur][1] += dp[y][0];
}
dp[cur][1]+=hap[cur];//cur节点要参加,自己的快乐指数也要加上
}
int main(){
cin >> n;
for(int i = 1;i<= n;i++){
cin >> hap[i];
}
int a,b;
for(int i = 0;i<n-1;i++){
cin >> a >> b;
ver[b].push_back(a);//b->a
isR[a] = 1;
}
//先找出根序号
for(int i = 1;i<=n;i++){
if(!isR[i])//说明节点i是根节点
{
root = i; dfs(i);
}
}
//cout << root<<"\n";
cout << max(dp[root][0],dp[root][1])<<"\n";
}