• 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的一些解析和题目:

      传送门

  • 相关阅读:
    mybatis中的#和$的区别
    Java 导出 CSV
    java生成UUID
    Java并发编程的艺术(七)——Executors
    Java并发编程的艺术(六)——线程间的通信
    Java并发编程的艺术(五)——中断
    Java并发编程的艺术(四)——线程的状态
    Java并发编程的艺术(三)——volatile
    Java并发编程的艺术(二)——重排序
    Java并发编程的艺术(一)——并发编程需要注意的问题
  • 原文地址:https://www.cnblogs.com/xwh-blogs/p/12889609.html
Copyright © 2020-2023  润新知