zoukankan      html  css  js  c++  java
  • 【树形DP】洛谷1122_最大子树和

    又是一道树形DP的入门题,思想非常简单  然而我最开始还是存了两个状态[传送门]


    题目描述

    小明对数学饱有兴趣,并且是个勤奋好学的学生,总是在课后留在教室向老师请教一些问题。一天他早晨骑车去上课,路上见到一个老伯正在修剪花花草草,顿时想到了一个有关修剪花卉的问题。于是当日课后,小明就向老师提出了这个问题:

    一株奇怪的花卉,上面共连有NN朵花,共有N-1N1条枝干将花儿连在一起,并且未修剪时每朵花都不是孤立的。每朵花都有一个“美丽指数”,该数越大说明这朵花越漂亮,也有“美丽指数”为负数的,说明这朵花看着都让人恶心。所谓“修剪”,意为:去掉其中的一条枝条,这样一株花就成了两株,扔掉其中一株。经过一系列“修剪“之后,还剩下最后一株花(也可能是一朵)。老师的任务就是:通过一系列“修剪”(也可以什么“修剪”都不进行),使剩下的那株(那朵)花卉上所有花朵的“美丽指数”之和最大。

    老师想了一会儿,给出了正解。小明见问题被轻易攻破,相当不爽,于是又拿来问你。

    输入输出格式

    输入格式:

    第一行一个整数N(1 ≤ N ≤ 16000)N(1N16000)。表示原始的那株花卉上共NN朵花。

    第二行有NN个整数,第II个整数表示第II朵花的美丽指数。

    接下来N-1N1行每行两个整数a,ba,b,表示存在一条连接第aa 朵花和第bb朵花的枝条。

    输出格式:

    一个数,表示一系列“修剪”之后所能得到的“美丽指数”之和的最大值。保证绝对值不超过21474836472147483647。

    样例输入:

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

    样例输出:

    3


    如你所见这是一道背景略显智障非常好的题,我们来简化一下题目:

    给定一个多叉树,每个点有一个权值。现在要做的就是保留或者不保留每个点,并且如果A是B和C的父节点,如果不保留A,那么B和C也不能保留。

    那么我们需要求的就是最后能够保留的最大值。

    于是最开始我是这么想的用f[u][0/1]来表示u节点的去留时所在子树的最大值,然后我弄完之后,因为智障而搞错了答案的存储,然后debug后突然想。。。既然0表示不选,那我为什么还要定义一个状态?????看来是我沙雕了。

    那么既然定义出来了,就非常容易想到代码,代码如下:

     1 #include<bits/stdc++.h>
     2 #define Add(X,Y) add((X),(Y)),add((Y),(X))
     3 #define INF 1<<31  
     4 namespace Jason{
     5 #define Xuxp(X,Y,Z) for(int (X)=(Y);(X)<=(Z);++i)
     6 #define Xuxs(X,Y,Z) for(int (X)=(Y);(X)>=(Z);--i)
     7 inline void scan(int &x){
     8     int f=1;x=0;char s=getchar();
     9     while(s<'0' || s>'9'){if(s=='-') f=-1;s=getchar();}
    10     while(s>='0' && s<='9'){x=x*10+s-'0';s=getchar();}
    11     x*=f;
    12 }
    13 inline void print(int x){
    14         if(x<0){putchar('-');x=-x;}
    15         if(x>9)print(x/10);char s=x%10+'0';
    16         putchar(s);
    17     }
    18 }
    19 using namespace std;
    20 using namespace Jason;
    21 const int maxn=16000+5;
    22 //--------------------
    23 struct Edge{
    24     int to,nxt;
    25 }edge[maxn<<1];int cnt=0,head[maxn];
    26 int n,f[maxn];
    27 //--------------------
    28 inline void add(int x,int y)
    29 {
    30     edge[++cnt].nxt=head[x]; 
    31     edge[cnt].to=y;
    32     head[x]=cnt;
    33 }
    34 inline void dp(int u,int fa)
    35 {
    36     for(int i=head[u];i!=-1;i=edge[i].nxt)
    37     {
    38         int v=edge[i].to;
    39         if(v==fa) continue;
    40         dp(v,u);
    41         f[u]+=max(f[v],0);
    42     }
    43 }
    44 int main()
    45 {
    46     int a,b;
    47     memset(head,-1,sizeof(head));
    48     scan(n);
    49     Xuxp(i,1,n) scan(f[i]);
    50     Xuxp(i,1,n-1) scan(a),scan(b),Add(a,b);
    51     dp(1,0);
    52     int Max=-INF;
    53     for(int i=1;i<=n;++i) if(f[i]>Max) Max=f[i];
    54     print(Max);
    55     return 0;
    56 }

    QAQ

    【正在纠结买不买无限正义高达。。。。。。。】

  • 相关阅读:
    BZOJ3781 小B的询问
    BZOJ3757 苹果树
    BZOJ1491 [NOI2007]社交网络
    BZOJ3754 Tree之最小方差树
    BZOJ1251 序列终结者
    BZOJ2259 [Oibh]新型计算机
    BZOJ1043 [HAOI2008]下落的圆盘
    D. 预定义变量
    A. 变量命名原则
    B. PHP变量的特点
  • 原文地址:https://www.cnblogs.com/JasonY1337357025/p/10295141.html
Copyright © 2011-2022 走看看