• [POI2014][树形DP]FarmCraft


    题目

    In a village called Byteville, there are houses connected with N-1 roads. For each pair of houses, there is a unique way to get from one to another. The houses are numbered from 1 to . The house no. 1 belongs to the village administrator Byteasar. As part of enabling modern technologies for rural areas framework, computers have been delivered to Byteasar's house. Every house is to be supplied with a computer, and it is Byteasar's task to distribute them. The citizens of Byteville have already agreed to play the most recent version of FarmCraft (the game) as soon as they have their computers. Byteasar has loaded all the computers on his pickup truck and is about to set out to deliver the goods. He has just the right amount of gasoline to drive each road twice. In each house, Byteasar leaves one computer, and immediately continues on his route. In each house, as soon as house dwellers get their computer, they turn it on and install FarmCraft. The time it takes to install and set up the game very much depends on one's tech savviness, which is fortunately known for each household. After he delivers all the computers, Byteasar will come back to his house and install the game on his computer. The travel time along each road linking two houses is exactly 1 minute, and (due to citizens' eagerness to play) the time to unload a computer is negligible. Help Byteasar in determining a delivery order that allows all Byteville's citizens (including Byteasar) to start playing together as soon as possible. In other words, find an order that minimizes the time when everyone has FarmCraft installed.

    mhy住在一棵有n个点的树的1号结点上,每个结点上都有一个妹子。

    mhy从自己家出发,去给每一个妹子都送一台电脑,每个妹子拿到电脑后就会开始安装zhx牌杀毒软件,第i个妹子安装时间为

    树上的每条边mhy能且仅能走两次,每次耗费1单位时间。mhy送完所有电脑后会回自己家里然后开始装zhx牌杀毒软件。

    卸货和装电脑是不需要时间的。

    求所有妹子和mhy都装好zhx牌杀毒软件的最短时间。

    输入格式

    The first line of the standard input contains a single integer N(2<=N<=5 00 000) that gives the number of houses in Byteville.

    The second line contains N integers C1,C2……Cn(1<= C<=109), separated by single spaces; Ci is the installation time (in minutes) for the dwellers of house no. i.

    The next N-1 lines specify the roads linking the houses. Each such line contains two positive integers a and b(1<=a<b<=N) , separated by a single space. These indicate that there is a direct road between the houses no. a and b.

    输出格式

    The first and only line of the standard output should contain a single integer: the (minimum) number of minutes after which all citizens will be able to play FarmCraft together.

    样例输入

    6

    1 8 9 6 3 2

    1 3

    2 3

    3 4

    4 5

    4 6

    样例输出

    11

    数据范围与提示

    Explanation: Byteasar should deliver the computers to the houses in the following order: 3, 2, 4, 5, 6, and 1. The game will be installed after 11, 10, 10, 10, 8, and 9 minutes respectively, in the house number order. Thus everyone can play after 11 minutes.

    If Byteasar delivered the game in the following order: 3, 4, 5, 6, 2, and 1, then the game would be installed after: 11, 16, 10, 8, 6, and 7 minutes respectively. Hence, everyone could play only after 16 minutes,

    解说

    首先可以明确一个点的安装时间等于走到这个点的时间+安装时间,最后总时间就是所有点的时间中最长的。

    刚开始做这道题时深受昨天的Salesman影响,觉得还是需要贪心思想(虽然确实是用贪心,但最开始走偏了……),结合样例一想,突发奇想觉得时间长的肯定是需要先走,那么我就把所有儿子的时间排个序,先走时间长的,再走时间短的,走下一个的时间中再加上之前走兄弟的子树的时间即可。

    然后呢?喜提38分。

    再仔细想想这个贪心确实不对啊。万一有一个时间很短的儿子,但是这个儿子下面却还有时间很长的后代,那么它还是应该先选的。

    这不就尴尬了吗……(万恶的样例)

    那么既然这样,我们就不能先给儿子排序再遍历,而是应该先遍历每个儿子再根据遍历结果排序。

    (下文中f[i]代表 i 节点所有子树中最长的时间,a[i]代表 i 节点的时间,size[i]代表 i 子树的规模)

    假设 u 节点有儿子 x 和 y ,则如果先走 x 的话 u 的时间就为max(f[x]+1,f[y]+2*size[x]+1);同理,先走 y 的话 u 的时间就为max(f[y]+1,f[x]+2*size[y]+1),若先安装x合适,则必有2*size[x]+f[y]+1>2*size[y]+f[x]+1,即f[x]-2*size[y]<f[y]-2*size[x],既然这样,我们就按照f[]-size[]排序即可。

    (下面的代码里还有部分解说)

    代码

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 const int maxn=500000+5;
     4 int t,a[maxn],head[maxn],n,tot,f[maxn],size[maxn],q[maxn];
     5 struct node{
     6     int to,next;
     7 }e[2*maxn];
     8 inline int read(){
     9    int s=0,w=1;
    10    char ch=getchar();
    11    while(ch<'0'||ch>'9'){if(ch=='-')w=-1;ch=getchar();}
    12    while(ch>='0'&&ch<='9') s=s*10+ch-'0',ch=getchar();
    13    return s*w;
    14 }
    15 bool cmp(int x,int y){//比较函数 
    16     return f[x]-2*size[x]>f[y]-2*size[y];
    17 }
    18 void Add(int from,int to){
    19     e[tot].to=to;
    20     e[tot].next=head[from];
    21     head[from]=tot;
    22     tot++;
    23 }
    24 void dfs(int u,int fa){
    25     int cnt=0,sum=1;//sum为走u子树目前的总时间
    26     //cnt为儿子的数量 
    27     if(u==1) f[u]=0;
    28     else f[u]=a[u];
    29     size[u]=1;//叶子节点没有子树size就会存为1 
    30     for(int i=head[u];i;i=e[i].next){
    31         int v=e[i].to;
    32         if(v!=fa){
    33             dfs(v,u);
    34             size[u]+=size[v];//统计规模 
    35         }
    36     }
    37     for(int i=head[u];i;i=e[i].next) if(e[i].to!=fa) q[++cnt]=e[i].to; 
    38     //q数组一定要用一个,不要一个dfs开一个,会直接爆掉(亲身经历) 
    39     sort(q+1,q+1+cnt,cmp);//贪心排序 
    40     for(int i=1;i<=cnt;i++){
    41         f[u]=max(f[u],f[q[i]]+sum);
    42         sum+=2*size[q[i]];
    43     }
    44 }
    45 int main(){
    46     tot=1;
    47     n=read();
    48     for(int i=1;i<=n;i++) a[i]=read();
    49     for(int i=1;i<=n-1;i++){
    50         int x=read(),y=read();
    51         Add(x,y);
    52         Add(y,x);
    53     }
    54     dfs(1,0);
    55     printf("%d",max(f[1],a[1]+2*(n-1)));
    56     return 0;
    57 } 
    View Code

    幸甚至哉,歌以咏志。

  • 相关阅读:
    iOS电商类App研发学习总结
    Swift4.0复习闭包
    Swift4.0复习函数
    Swift4.0复习Optional
    SQL面试题
    sql(join on 和where的执行顺序)
    算法四:回溯和分支界定
    算法三:贪婪算法
    编程之美2.11:寻找最近的点对
    编程之美2.5:寻找最大的K个数
  • 原文地址:https://www.cnblogs.com/DarthVictor/p/12640712.html
Copyright © 2020-2023  润新知