P1352 没有上司的舞会

题目描述:

  传送门

题解思路:

首先题目中发明确告诉了是一棵树,所以在输入数据后应该构建一棵树来储存这些数据。

这是一道非常经典的树形dp问题,对每个结点dp[i][0]表示不邀请这个员工,其子树达到的最大快乐值,dp[i][1]表示邀请i员工其子树达到的最大值,对于每个结点的状态应该从这两方面去考虑。
dp[i][0]=(i的全部员工的max(dp[u][1],dp[u][0)相加,也就是其子员工来或不来的最大快乐值。
dp[i][1]=(i的全部员工的dp[u][0相加,也就是其子员工都不能不来的最大快乐值。
从根结点开始dp,最终结果就是max(dp[root][0],dp[root][1])

 

题目代码

#include<iostream>
#include<algorithm>
using namespace std;
#define INF 1000000

int n=0;
int root=-1; 
int r[6005];
int p[6005]={0};        //专门用于找根节点 
int flag[6005]={0};        //flag[i]判断结点i是否参加聚会 
int dp[6005][2];
struct node{        //树的结点 
    int size;
    int c[200];        //保存子节点的编号     c数组要开的大一点 防止不够 
};
node dd[6000];
void dfs(int i){   
    dp[i][1]=r[i];   //i参加聚会 把自己的快乐值先加上 
 
for(int j=0;j<dd[i].size;j++){   int son=dd[i].c[j];    //找i的孩子 if(son>0){ dfs(son); dp[i][0]+=max(dp[son][0],dp[son][1]);  //若i不参加聚会,则i的孩子们有两种选择 dp[i][1]+=dp[son][0];  //i参加聚会 则i的孩子无法参加 } } } int main(){ cin>>n; for(int i=1;i<=n;i++){ cin>>r[i]; } for(int i=1;i<=n-1;i++){    //用结构体数组来存树 int a,b; cin>>a>>b; //b是上司 dd[b].c[dd[b].size++]=a; p[a]=1; //代表a不是根 } for(int i=1;i<=n;i++){ if(p[i]==0){ root=i; //找到根节点 break; } } for(int i=1;i<=n;i++){ dp[i][0]=0; dp[i][1]=0; } dfs(root); cout<<max(dp[root][0],dp[root][1]);//注意dp[root][1]在dfs中已经加过r[root] return 0; }

 

 

关于树形dp的一些解析和题目:

  传送门

posted @ 2020-05-14 16:34  neverstopcoding  阅读(188)  评论(0编辑  收藏  举报