zoukankan      html  css  js  c++  java
  • 洛谷 P1271 聚会的快乐(树状dp)

    题目描述

    你要组织一个由你公司的人参加的聚会。你希望聚会非常愉快,尽可能多地找些有趣的热闹。但是劝你不要同时邀请某个人和他的上司,因为这可能带来争吵。给定N个人(姓名,他幽默的系数,以及他上司的名字),编程找到能使幽默系数和最大的若干个人。

    输入输出格式

    输入格式:

    第一行一个整数N(N<100)。接下来有N行,每一行描述一个人的信息,信息之间用空格隔开。姓名是长度不超过20的字符串,幽默系数是在0到100之间的整数。

    输出格式:

    所邀请的人最大的幽默系数和。

    输入输出样例

    输入样例#1:
    5
    BART 1 HOMER
    HOMER 2 MONTGOMERY
    MONTGOMERY 1 NOBODY
    LISA 3 HOMER
    SMITHERS 4 MONTGOMERY
    输出样例#1:
    8
    
    这道题是一道树状dp的入门题目,树状dp的基本思想就是从某节点依次向下层递归,其实和经典的数塔问题没什么区别,这个题就是每个人可以有多个下属(每个节点可以有多个儿子)。
    然后难点就是当此节点的人参加聚会时和不参加聚会时的情况处理,详细解释已经写到注释里了。
    代码如下:
     1 #include <bits/stdc++.h>
     2 
     3 using namespace std;
     4 #define inf 0x3f3f3f3f
     5 int n,dp[110][2],value[110],son[110],vson[110][110],topnode,ans;
     6 /*
     7 dp[i][0]表示不让第i人参加聚会的最大值,dp[i][1]让第i个人参见聚会的最大值
     8 value[i]表示第i人的幽默系数
     9 son[i]表示第i个人有多少个下属  vson[i][j]表示第i人的第j个下属是谁
    10 topnode 表示整个公司最上层的人,她没有上司
    11 */
    12 bool vis[110][110];//记忆化搜索的标记数组
    13 string namee[110],upp[110];//分别表示第i人的名字和其上司的名字
    14 int dfs(int i,int j)
    15 {
    16     if (vis[i][j])
    17     return dp[i][j];
    18     vis[i][j]=true;
    19     if (i==0)
    20     return 0;
    21     if (j==1)//这个人参加聚会
    22     {
    23         dp[i][j]=value[i];
    24         for (int k=1;k<=son[i];++k)
    25         dp[i][j]+=dfs(vson[i][k],0);//他的下属都不能参加聚会,在这条件下找最大值
    26     }
    27     else//人不参加聚会
    28     {
    29         for (int k=1;k<=son[i];++k)
    30         dp[i][j]+=max(dfs(vson[i][k],0),dfs(vson[i][k],1));//他的下属可以有参加或者不参加两种情况
    31     }
    32     return dp[i][j];
    33 }
    34 int main()
    35 {
    36     
    37     //freopen("de.txt","r",stdin);
    38     scanf("%d",&n);
    39     memset(son,0,sizeof son);
    40     memset(dp,0,sizeof dp);
    41     memset(vson,0,sizeof vson);
    42     memset(vis,false,sizeof vis);
    43     for (int i=1;i<=n;++i)
    44     cin>>namee[i]>>value[i]>>upp[i];
    45     for (int i=1;i<=n;++i)
    46     {
    47         bool haveUpp=false;//haveupp表示该人是否有上司
    48         for (int j=1;j<=n;++j)
    49         {
    50             if (i==j)
    51             continue;
    52             if (namee[j]==upp[i])
    53             {
    54                 haveUpp=true;
    55                 vson[j][++son[j]]=i;//把上下属关系处理
    56                 break;
    57             }
    58         }
    59         if (!haveUpp)
    60         topnode=i;
    61     }
    62     ans=max(dfs(topnode,0),dfs(topnode,1));//因为最上层的人也有参加不参加两种可能
    63     printf("%d
    ",ans);
    64     return 0;
    65 }
    
    
  • 相关阅读:
    bzoj1711: [Usaco2007 Open]Dining吃饭
    bzoj1036: [ZJOI2008]树的统计Count
    bzoj1497: [NOI2006]最大获利
    bzoj2561: 最小生成树
    BZOJ 2083: [Poi2010]Intelligence test( )
    BZOJ 2212: [Poi2011]Tree Rotations( 线段树 )
    BZOJ 1110: [POI2007]砝码Odw( 贪心 )
    BZOJ 3163: [Heoi2013]Eden的新背包问题( 背包dp )
    BZOJ 1537: [POI2005]Aut- The Bus(dp + BIT)
    BZOJ 2875: [Noi2012]随机数生成器( 矩阵快速幂 )
  • 原文地址:https://www.cnblogs.com/agenthtb/p/5849482.html
Copyright © 2011-2022 走看看