• 树形DP--codevs 1380 没有上司的舞会


    codevs 1380 没有上司的舞会

    变式题目:给定一棵树每个点有一个点权,求一个独立集使得点权和最大,树上的独立集指的是选取树上的点,使尽量多的点不直接相连

     时间限制: 1 s
     空间限制: 128000 KB
     题目等级 : 钻石 Diamond 
    题目描述 Description

          Ural大学有N个职员,编号为1~N。他们有从属关系,也就是说他们的关系就像一棵以校长为根的树,父结点就是子结点的直接上司。每个职员有一个快乐指数。现在有个周年庆宴会,要求与会职员的快乐指数最大。但是,没有职员愿和直接上司一起与会。

    输入描述 Input Description

    第一行一个整数N。(1<=N<=6000)
    接下来N行,第i+1行表示i号职员的快乐指数Ri。(-128<=Ri<=127)
    接下来N-1行,每行输入一对整数L,K。表示K是L的直接上司。
    最后一行输入0,0。

    输出描述 Output Description

    输出最大的快乐指数。

    样例输入 Sample Input

    7
    1
    1
    1
    1
    1
    1
    1
    1 3
    2 3
    6 4
    7 4
    4 5
    3 5
    0 0

    样例输出 Sample Output

    5

    数据范围及提示 Data Size & Hint

    各个测试点1s

    分类标签 Tags

    动态规划 树型DP

     1 /*树形Dp:一般以节点作为状态划分的点。
     2       对于当前的节点代表的人:
     3        1.这个人去舞会,那么他的下属一定不去,状态转移到子节点
     4        2.这个人不去舞会,但是他的下属也不一定会去,因为不一定是最优,就是在子节点去与不去间取最优 
     5       树形Dp一般从根节点开始记忆化搜索来实现。 
     6 */
     7 #include<iostream>
     8 using namespace std;
     9 #include<cstdio>
    10 #define N 8000
    11 struct Edge{
    12     int v,last;
    13 }edge[N];
    14 bool flag[N];/*找根节点*/
    15 int f[N][2],val[N];/*f[i][1]代表当前节点去舞会的这棵子树上快乐最大值,f[i][0]代表当前节点不去舞会的这棵子树上快乐最大值,*/
    16 int head[N]={0},cnt=0;
    17 int n;
    18 void add_edge(int u,int v)
    19 {
    20     ++cnt;
    21     edge[cnt].v=v;/*建立边表*/
    22     edge[cnt].last=head[u];
    23     head[u]=cnt;
    24 }
    25 void dp(int u)
    26 {
    27     f[u][0]=0;/*搜索的边界就是没有下属的人,就是f[u][1]=val[u];    f[u][0]=0;*/
    28     f[u][1]=val[u];
    29     for(int l=head[u];l;l=edge[l].last)/*对于有下属的人,必须知道他的下属情况才能判断*/
    30     {
    31         int v=edge[l].v;
    32         dp(v);/*搜索下属*/
    33         f[u][1]=max(f[u][1],f[u][1]+f[v][0]);/*注意这是在for循环中当前点的f[v][0]会被加了多次,v不同*/
    34         f[u][0]=f[u][0]+max(f[v][1],f[v][0]);/*当前节点不去,就判断他的某个子节点去还是不去最优*/
    35     }
    36 }
    37 int main()
    38 {
    39     scanf("%d",&n);
    40     for(int i=1;i<=n;++i)
    41       scanf("%d",&val[i]);
    42     for(int i=1;i<n;++i)
    43     {
    44         int u,v;
    45         scanf("%d%d",&v,&u);
    46         flag[v]=true;/*给有父节点的点标上标记*/
    47         add_edge(u,v);
    48     }
    49     int u,v;
    50     scanf("%d%d",&u,&v);
    51     for(int i=1;i<=n;++i)
    52       if(!flag[i])/*找到根节点*/
    53       {
    54           dp(i);
    55           printf("%d
    ",max(f[i][0],f[i][1]));
    56           break;
    57       }
    58     return 0;
    59 }
  • 相关阅读:
    在linux上搭建sftp服务
    FTP客户端遇到150连接超时错误的处理办法
    电脑每次开机打开微软网站怎么解决
    Linux学习笔记之认识与学习Bash
    Linux学习笔记之VIM编辑器
    Linux学习笔记之文件与文件系统的压缩与打包
    Linux学习笔记之磁盘与文件系统的管理
    Linux学习笔记之目录配置
    Linux学习笔记之档案权限与目录配置
    ubuntu修改apt源
  • 原文地址:https://www.cnblogs.com/c1299401227/p/5488727.html
Copyright © 2020-2023  润新知