zoukankan      html  css  js  c++  java
  • [POI2014]FAR-FarmCraft 树形DP + 贪心思想


    (感觉洛谷上题面那一小段中文根本看不懂啊,好多条件都没讲,直接就是安装也要一个时间啊,,,明明不止啊!还好有百度翻译。。。。。。

    题意:一棵树,一开始在1号节点(root),边权都为1,每个点有点权,要最小化max(点权+到达时间) <---所有点的

    首先这看起来就是一道DP题,但是根据直觉,,,应该跟贪心挂钩,因为感觉耗时久的要先去是吧

    但是我们发现并不能这么弄,因为去一棵子树就要走完它,这个时候再去别的树的时候可能已经很晚了,所以就不一定优了

    不过我们可以发现,从一个点出发,去节点的顺序就决定了答案

    于是我们考虑排序

    但是节点太多比较难以分析,因此我们先以两个儿子为例分析。

    f[i]代表以i为根的最大时长,

    于是目的就是最小化f[1],size[i]代表遍历这个点要多久,

    因为要遍历完这个子树才可以去另一棵,于是就有转移方程:

    f[i]=max(f[a],f[b] + size[a] + 2),其中a,b为两棵子树,+2是去a的那条边来回的时间,这个是先去a的,

    f[i]=max(f[b],f[a] + size[b] + 2),然后就是最小化这4个式子中的最大值,

    PS:等等,,,貌似是f[a]+1????,懒得改了,,,大家自行脑补成f[a]+1吧,不影响结果

    于是先按照国王游戏里面的方法来推导一下:

    首先设先去a比较优,

    那么有max(f[a],f[b] + size[a] + 2) < max(f[b],f[a] + size[b] + 2)

    因为f[a] + size[b] + 2 > f[a],f[b] + size[a] + 2 > f[b],

    所以这4个式子的最大值不可能会是f[a] or f[b],

    所以要使得等式成立就只能寄希望于

    f[b] + size[a] + 2 < f[a] + size[b] + 2

    所以以这个为条件排序即可

    各种细节QAQ调了好久

     1 #include<bits/stdc++.h>
     2 using namespace std;
     3 #define R register int
     4 #define AC 501000
     5 #define getchar() *o++
     6 #define LL long long
     7 char READ[40001000],*o=READ;
     8 int n,ans;
     9 int cost[AC],size[AC];
    10 int date[AC * 2],Next[AC * 2],Head[AC],tot;
    11 struct point{
    12     int size;
    13     LL f;
    14 }p[AC];
    15 LL f[AC];
    16 inline int read()
    17 {
    18     int x=0;char c=getchar();
    19     while(c > '9' || c < '0') c=getchar();
    20     while(c >= '0' && c <= '9') x=x*10+c-'0',c=getchar();
    21     return x;
    22 }
    23 
    24 inline void add(int f,int w)
    25 {
    26     date[++tot]=w,Next[tot]=Head[f],Head[f]=tot;
    27     date[++tot]=f,Next[tot]=Head[w],Head[w]=tot;
    28 }
    29 
    30 inline bool cmp(point a,point b)
    31 {
    32     return b.f + a.size < a.f + b.size;
    33 }
    34 
    35 void pre()
    36 {
    37     R a,b;
    38     n=read();
    39     for(R i=1;i<=n;i++) cost[i]=read();
    40     for(R i=1;i<n;i++)
    41     {
    42         a=read(),b=read();
    43         add(a,b);
    44     }
    45 }
    46 
    47 void DFS(int x,int fa)//还是要传father,不然的话下面加入队列的部分就判断不了了,因为这时下面都已经访问过了
    48 {
    49     int now,tot=0;
    50     if(x != 1) f[x] = cost[x];//至少自己要装啊,但是注意第一个是最后装的
    51     for(R i=Head[x]; i ;i=Next[i])
    52     {
    53         now=date[i];
    54         if(now == fa) continue;
    55         DFS(now,x);
    56     }
    57     for(R i=Head[x]; i ;i=Next[i]) 
    58     {
    59         now=date[i];
    60         if(now != fa) 
    61             p[++tot]=(point) {size[now],f[now]};//不能在上面加,因为一旦下一次调用了DFS,队列里就乱了
    62     }
    63     sort(p+1,p+tot+1,cmp);
    64     for(R i=1;i<=tot;i++)
    65     {
    66         f[x]=max(f[x],p[i].f + size[x] + 1);
    67         size[x] += p[i].size + 2;//反正这样也是统计了一样的东西
    68     }
    69 }
    70 
    71 int main()
    72 {
    73     freopen("in.in","r",stdin);
    74     fread(READ,1,40000000,stdin);
    75     pre();
    76     DFS(1,0);
    77     printf("%lld
    ",max(f[1],(LL)(n * 2 - 2 + cost[1])));
    78     fclose(stdin);
    79     return 0;
    80 }

    [POI2014]FAR-FarmCraft

  • 相关阅读:
    Two sum 两个数相加
    [ACM] hdu 1286 找新朋友(欧拉函数)
    环形队中实现队列的基本运算
    队列的顺序存储结构及其基本运算的实现
    栈的链式存储结构及其基本运算实现
    栈的顺序存储结构及其基本运算实现
    [ACM] hdu 1205 吃糖果(鸽巢原理)
    [ACM] poj 3128 Leonardo's Notebook (置换群,循环节)
    hdu acm 1051 Zipper
    [ACM] poj 2369 Permutations (置换群循环节长度)
  • 原文地址:https://www.cnblogs.com/ww3113306/p/8998162.html
Copyright © 2011-2022 走看看