zoukankan      html  css  js  c++  java
  • 【BZOJ 3090】 树形DP

    3090: Coci2009 [podjela]

    Description

    有 N 个农民, 他们住在 N 个不同的村子里. 这 N 个村子形成一棵树.
    每个农民初始时获得 X 的钱.
    每一次操作, 一个农民可以从它自己的钱中, 取出任意数量的钱, 交给某个相邻村子的农民.

    对于每个农民给定一个值 v_i, 求
        (1) 最少需要多少次操作, 使得每个农民最终拿到的钱 >= 给定的值.

    Input

        第1行: 一个整数 N (1 <= N <= 2000)
        第2行: 一个整数 X (0 <= X <= 10000)
        第3行: N 个整数, 表示 v_i. 保证所有 v_i 的和 <= N * X
        第4..N+2行: 每行两个 1..N 的数, 表示树上的一条边. 边是双向的.

    Output

        第1行: 一个整数, 最少需要的操作次数

    Sample Input

    6
    15
    10 20 18 16 6 16
    1 4
    4 5
    4 6
    6 2
    5 3

    Sample Output

    5

    HINT

    Source

    【分析】

      之前做过很多次这种移来移去的题目了。

      如果有环的,我就做过BZOJ 1045 一道数学题。

      如果没环,目标值的和等于初始值的和,那么挺唯一的,直接for就好了。

      这题就是目标值的和小于等于初始值的和的,考虑DP。

      一开始的想法当然是f[x][y]表示x这个子树,然后y这个点的值,然后什么最小代价。

      但是爆空间超时啊,不如把f中的y和答案换一下位置,因为显然操作次数少于子树大小,

      f[x][y]表示x这棵子树在操作y次之后满足目标值,最少要x从父亲那里拿多少东西(若f的值小于0则表示不仅不用从父亲那里拿东西,还可以给-f[x][y]的东西给父亲)

      然后DP。

      这种要满足每个子树的题我真的是不太擅长,于是我最好的解决方案就是滚动一下了。

      还有要注意的是x<=n,y<=x,所以看似三重循环,实际是n^2的,这个是之前做树形依赖的题知道的,因为可以看成只会在LCA的时候for到那两个东西。

      

      大神的方法跟我的差不多然后讲的比我清楚:http://blog.csdn.net/visit_world/article/details/54297322

     1 #include<cstdio>
     2 #include<cstdlib>
     3 #include<cstring>
     4 #include<iostream>
     5 #include<algorithm>
     6 using namespace std;
     7 #define Maxn 2010
     8 #define INF 0xfffffff
     9 
    10 int mymin(int x,int y) {return x<y?x:y;}
    11 int mymax(int x,int y) {return x>y?x:y;}
    12 
    13 int w[Maxn],ww;
    14 
    15 struct node
    16 {
    17     int x,y,next;
    18 }t[Maxn*2];
    19 int first[Maxn],len;
    20 
    21 void ins(int x,int y)
    22 {
    23     t[++len].x=x;t[len].y=y;
    24     t[len].next=first[x];first[x]=len;
    25 }
    26 
    27 int f[Maxn][Maxn],g[2][Maxn],sm[Maxn];
    28 
    29 void dfs(int x,int ff)
    30 {
    31     sm[x]=1;
    32     for(int i=first[x];i;i=t[i].next) if(t[i].y!=ff)
    33     {
    34         int y=t[i].y;
    35         dfs(y,x);
    36         sm[x]+=sm[y];
    37     }
    38     if(sm[x]!=1)
    39     {
    40         int p=0;
    41         for(int j=0;j<=sm[x];j++) g[0][j]=0;
    42         for(int i=first[x];i;i=t[i].next) if(t[i].y!=ff)
    43         {
    44             int y=t[i].y;
    45             for(int j=0;j<=sm[x];j++) g[1-p][j]=INF;
    46             //j-k<=sm[x]-1-sm[y]
    47             //k>=j-sm[x]+sm[y]+1
    48             for(int j=0;j<=sm[x];j++)
    49             {
    50                 int st=mymax(j-sm[x]+sm[y]+1,0);
    51                 for(int k=st;k<=sm[y];k++)
    52                 {
    53                     if(k>j) break;//j-k>=0
    54                     if(f[y][k]>0)
    55                     {
    56                         if(k>=1) g[1-p][j]=mymin(g[1-p][j],g[p][j-k]+f[y][k-1]);
    57                     }
    58                     else
    59                     {
    60                         if(k>=1) g[1-p][j]=mymin(g[1-p][j],g[p][j-k]+f[y][k-1]);//give father
    61                         if(k!=sm[y]) g[1-p][j]=mymin(g[1-p][j],g[p][j-k]);
    62                     }
    63                 }
    64             }
    65             p=1-p;
    66         }
    67         for(int j=0;j<sm[x];j++) f[x][j]=g[p][j];
    68     }
    69     for(int j=0;j<sm[x];j++)
    70     {
    71         f[x][j]=f[x][j]+w[x]-ww;
    72         // printf("f[%d][%d]=%d
    ",x,j,f[x][j]);
    73     }
    74 }
    75 
    76 int main()
    77 {
    78     int n;
    79     scanf("%d%d",&n,&ww);
    80     len=0;
    81     memset(first,0,sizeof(first));
    82     for(int i=1;i<=n;i++) scanf("%d",&w[i]);
    83     for(int i=1;i<n;i++)
    84     {
    85         int x,y;
    86         scanf("%d%d",&x,&y);
    87         ins(x,y);ins(y,x);
    88     }
    89     memset(f,0,sizeof(f));
    90     dfs(1,0);
    91     for(int i=0;i<sm[1];i++) if(f[1][i]<=0) {printf("%d
    ",i);break;}
    92     return 0;
    93 }
    View Code

    2017-03-22 10:26:09

  • 相关阅读:
    open jdk卸载
    “玲珑杯”ACM比赛 Round #18---图论你先敲完模板(DP+思维)
    “玲珑杯”ACM比赛 Round #18--最后你还是AK了(搜索+思维)
    hdu 5116--Everlasting L(计数DP)
    HDU 5113--Black And White(搜索+剪枝)
    hdu 5573---Binary Tree(构造)
    HDU 5517---Triple(二维树状数组)
    hdu 5975---Aninteresting game(树状数组)
    hdu 5972---Regular Number(字符串匹配)
    HDU 4570---Multi-bit Trie(区间DP)
  • 原文地址:https://www.cnblogs.com/Konjakmoyu/p/6598528.html
Copyright © 2011-2022 走看看