• 树上的石头


    原题:https://cn.vjudge.net/problem/TopCoder-14812

    http://210.33.19.103/contest/1002/problem/4

    树上的石头

    时间:1s   空间:256M

    题目描述:

    给你一棵树,标号为0到n-1,0为根节点,每个点有点权
    现在你可以在一些点上放石头,也可以拿掉某些点上的石头
    一个点可以放石头当且仅当这个点的所有儿子都放上了石头
    如果根节点放上石头任务完成
    求在整个过程中放着石头的节点的点权之和的最大值的最小值( 也就是说你要选择一个合理的顺序放置石头来使得答案最优)

    输入格式:

    第一行输入一个整数$n$ ($2 le n le 1000$)

    第二行输入$n-1$个整数$p[0]->p[n-2]$, $p[i]$表示$(i+1)$与$p[i]$之间有一条边,$0 le p[i] le i$

    第三行输入n个整数表示每个点的点权,$1 le w[i] le 10^5$ , w非减

    输出格式:

    输出一个整数

    样例输入1:

    5
    0 1 2 3
    1 2 2 4 4
    

    样例输出1:

    8 

    样例输入2:

    5
    0 0 0 0 
    1 2 3 4 5
    

    样例输出2:

    15

    样例一解释:

    {0,1,2,3} //分别表示1的父亲 2的父亲 3的父亲 4的父亲
    {1,2,2,4,4}//每个点的点权值
    Returns: 8
    五个节点构成了一条链
    在节点4上放一个石头 (权值和 = 4).
    在节点3上放一个石头 (权值和 = 8).
    移除节点4上的石头   (权值和 = 4).
    在节点2上放一个石头 (权值和 = 6).
    在节点1上放一个石头 (权值和 = 8).
    移除节点2上的石头   (权值和 = 6)
    在节点0(根节点)上放一个石头 (权值和 = 7)
    整个过程中最大的权值和为8,不存在比最大值比8小的方案了

    自己多造数据

    子任务一30分:n<=20

    子任务二30分:n<=100

    子任务三40分:n<=1000


    可能是常见贪心模型?感觉见过?然而不会

    找不到是哪里的模型了..好像跟蓝书前几页的一个经典贪心题很像?

    设f[i]=dfs(i),表示i节点为根子树的答案;d[i]表示i自身权值
    对于某个节点u来说,在确定其各个子节点的答案之后,实际上就是要确定放其子树中点的顺序
    放u某个子节点v的实际代价,是f[v]+(之前已经放好的u的子节点的权值(d)之和)
    错解:把子节点按f值排序,大的在前;由于可能导致某时刻d值和太大,导致不优
    正解:
    如果一种方案的顺序有i恰好在j之前,且f[i]-d[i]<f[j]-d[j]
    则设放i时之前的d值和为sum
    则放i,j时代价为max(f[i],f[j]+d[i])+sum;交换i,j,代价变为max(f[j],f[i]+d[j])+sum
    可以按f[i]与f[j]大小关系分类讨论,证明交换i,j后一定不会变得更劣(即不会变得更大)
    因此按照f[i]-d[i]从大到小排序即可

     1 #include<cstdio>
     2 #include<algorithm>
     3 #include<cstring>
     4 #include<vector>
     5 #include<functional>
     6 using namespace std;
     7 #define fi first
     8 #define se second
     9 #define mp make_pair
    10 #define pb push_back
    11 typedef long long ll;
    12 typedef unsigned long long ull;
    13 typedef pair<int,int> pii;
    14 int n;
    15 vector<int> ch[1010];
    16 int d[1030];
    17 struct
    18 {
    19     bool operator()(const pii &a,const pii &b)
    20     {
    21         return a.fi-a.se>b.fi-b.se;
    22     }
    23 }cmp;
    24 int dfs(int u)
    25 {
    26     vector<pii> tmp;
    27     for(auto v:ch[u])
    28     {
    29         tmp.pb(mp(dfs(v),d[v]));
    30     }
    31     sort(tmp.begin(),tmp.end(),cmp);
    32     int sum=0,an=0;
    33     for(int i=0;i<tmp.size();i++)
    34     {
    35         an=max(an,tmp[i].fi+sum);
    36         sum+=tmp[i].se;
    37     }
    38     //printf("1t%d %d
    ",u,an);
    39     return max(an,sum+d[u]);
    40 }
    41 int main()
    42 {
    43     int i,b;
    44     scanf("%d",&n);
    45     for(i=2;i<=n;i++)
    46     {
    47         scanf("%d",&b);b++;
    48         ch[b].pb(i);
    49     }
    50     for(i=1;i<=n;i++)    scanf("%d",&d[i]);
    51     printf("%d",dfs(1));
    52     return 0;
    53 }
    View Code
  • 相关阅读:
    UITextView 和 UITextField 的提示信息placeholder
    【转载】ios下的正则表达式,RegexKitLite
    Java集合(2)一 ArrayList 与 LinkList
    Java并发(2) 聊聊happensbefore
    Java并发(3) 聊聊Volatile
    Java并发(1) 聊聊Java内存模型
    Java集合(5)一 HashMap与HashSet
    Java集合(3)一 红黑树、TreeMap与TreeSet(上)
    Java集合(4)一 红黑树、TreeMap与TreeSet(下)
    Java集合(1)一 集合框架
  • 原文地址:https://www.cnblogs.com/hehe54321/p/9686638.html
Copyright © 2020-2023  润新知