• [FZYZOJ 1598] & [FZYZOJ 1298] 最大子树和(修剪花卉)


    P1598 P1298 -- [NOIP福建夏令营]最大子树和

    时间限制:1000MS

    内存限制:131072KB

    Description

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

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

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

    Input Format

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

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

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

    Output Format

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

    Sample Input

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

    Sample Output

    3

    Hint

    对于60%的数据,有N≤1000;

    对于100%的数据,有N≤16000。

    【题解】

    对于DP还不怎么熟

    算是我第一个写的树形DP吧

    树形DP其实是借助DFS来进行实现的。

    对于本题,设f[u]表示以u为顶点的子树的和的最大值(包括u),那么f[u]=sum{f[son]}+w[i] (f[son]>0)

    显然,对于叶子节点,f[u]=w[u];

    所以,我们可以用DFS来实现

    (感谢yjc大聚聚的指导)

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 int fs[16010],n,pre[40010],next[40010],last[40010],f[16010],num=0;
     4 bool vis[16010];
     5 int ans=-1;
     6 inline void add(int a,int b) {
     7     num++;
     8     next[num]=b;
     9     pre[num]=last[a];
    10     last[a]=num;
    11 }
    12 int dfs(int u) {
    13     int sum=0;
    14     if(f[u]) return f[u];
    15     int i=last[u];
    16     while(i) {
    17         int nxt=next[i];
    18         if(!vis[nxt]) {
    19             vis[nxt]=1;
    20             int x=dfs(nxt);
    21             if(x>0) sum+=x;
    22         }
    23         i=pre[i];
    24     }
    25     f[u]=sum+fs[u];
    26     if(f[u]>ans) ans=f[u];
    27     return f[u];
    28 }
    29 int main() {
    30     scanf("%d",&n);
    31     for (int i=1;i<=n;++i) scanf("%d",&fs[i]);
    32     for (int i=1;i<=n-1;++i) {
    33         int a,b;
    34         scanf("%d%d",&a,&b);
    35         add(a,b);
    36         add(b,a);
    37     }
    38     vis[1]=1;
    39     dfs(1);
    40     printf("%d
    ",ans);
    41 }
    View Code

    前面边集数组没开大导致了WA+TLE。。今天做什么题都不太顺啊=-=

    这篇文章由TonyFang发布。 所有解释权归TonyFang所有。 Mailto: tony-fang@map-le.net
  • 相关阅读:
    Zabbix基本配置及监控主机
    利用XAG在RAC环境下实现GoldenGate自动Failover
    Oracle Database 12c Data Redaction介绍
    使用Oracle官方巡检工具ORAchk巡检数据库
    浅谈C# 多态
    Qt 操作Excel
    一个适用于任何继承于QObject的类的创建工厂
    QT5 控件增加背景图片(可缩放可旋转)的几种方法
    值得推荐和学习的C/C++框架和库
    gcc/g++编译
  • 原文地址:https://www.cnblogs.com/TonyNeal/p/fzyzoj1598.html
Copyright © 2020-2023  润新知