zoukankan      html  css  js  c++  java
  • 【LOI2005】【P1306】河流

    树归题,本来比较简单,但是因为几个思想搞错了,所以卡了两天

    原题:

    几乎整个Byteland 王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——Bytetown。
      在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland 的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在 运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。
    注:所有的河流都不会分叉,形成一棵树,根结点是Bytetown。
      国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米1分钱。
      编一个程序: 
      1.从文件读入村子的个数,另外要建设的伐木场的数目,每年每个村子产的木料的块数以及河流的描述。 
      2.计算最小的运费并输出。

    n(2<=n<=100),k(1<=k<=50,且k<=n)

    常规树归思路:多叉转二叉,枚举中间值,分别搞兄弟和儿子

    不过这里要多加一维,表示离x最近的祖先伐木场,用up表示

    然后状态转移方程如下:

    不建站:f[x][up][y]=min(f[x][up][y],f[tree[x].brother][up][i]+f[tree[x].child][up][y-i]+cost);//因为不建站,所以y-i

    建:f[x][up][y]=min(f[x][up][y],f[tree[x].brother][up][i]+f[tree[x].child][x][y-i-1]);//因为建站,所以y-i-1

    这里有几点需要注意:

    跟其他树归不同的是,这里y==0也可以进行下去,因为有建和不建两种选择,所以就枚举0-y,在满足x有儿子且y-i-1的情况下才能去搞建站的情况,任何条件下都能搞不建站的情况

    如果这个节点建站,搞兄弟的时候兄弟的祖先伐木场依旧是x的祖先伐木场

    BZOJ上有此题,感觉以后某天可以再做一次

    代码:

     1 #include<iostream>
     2 #include<cstdio>
     3 #include<cstring>
     4 #include<algorithm>
     5 #include<cmath>
     6 using namespace std;
     7 struct dcd{int child,brother,father,value,s,sum;}tree[110];
     8 inline void insert(int x,int y,int z,int s){  tree[y].brother=tree[x].child;  tree[x].child=y;  tree[y].father=x;  tree[y].value=z;  tree[y].s=s;}
     9 void get_sum(int x){if(x==0)return ;  tree[x].sum=tree[x].s+tree[tree[x].father].sum;  get_sum(tree[x].brother);  get_sum(tree[x].child);}
    10 int n,m;
    11 int f[110][110][60];
    12 bool visited[110][110][60];
    13 void dp_tree(int x,int up,int y){
    14     if(visited[x][up][y])return ;  visited[x][up][y]=true;
    15     //cout<<x<<" "<<up<<" "<<y<<endl;
    16     if(!x || y<0){  f[x][up][y]=0;  return ;}
    17     if(tree[x].brother)  dp_tree(tree[x].brother,up,y);
    18     int cost=tree[x].value*(tree[x].sum-tree[up].sum);
    19     for(int i=0;i<=y;i++){
    20         dp_tree(tree[x].brother,up,i);  dp_tree(tree[x].child,up,y-i);//x不建,所以不-1
    21         f[x][up][y]=min(f[x][up][y],f[tree[x].brother][up][i]+f[tree[x].child][up][y-i]+cost);
    22         if(x!=n+1 && y-i-1>=0){
    23             dp_tree(tree[x].child,x,y-i-1);//建了,所以-1
    24             f[x][up][y]=min(f[x][up][y],f[tree[x].brother][up][i]+f[tree[x].child][x][y-i-1]);//注意brother的up还是up不是x
    25         }
    26     }
    27     //cout<<x<<" "<<up<<" "<<y<<" "<<f[x][up][y]<<endl;
    28 }
    29 int main(){//freopen("ddd.in","r",stdin);
    30     memset(f,20,sizeof(f));
    31     memset(visited,0,sizeof(visited));
    32     cin>>n>>m;
    33     int _value,_father,_s;
    34     for(int i=1;i<=n;i++){  cin>>_value>>_father>>_s;  if(!_father)_father=n+1;  insert(_father,i,_value,_s);}
    35     get_sum(n+1);
    36     dp_tree(n+1,n+1,m);
    37     cout<<f[n+1][n+1][m]<<endl;
    38     return 0;
    39 }
    View Code
  • 相关阅读:
    nginx-1.8.1的安装
    ElasticSearch 在3节点集群的启动
    The type java.lang.CharSequence cannot be resolved. It is indirectly referenced from required .class files
    sqoop导入导出对mysql再带数据库test能跑通用户自己建立的数据库则不行
    LeetCode 501. Find Mode in Binary Search Tree (找到二叉搜索树的众数)
    LeetCode 437. Path Sum III (路径之和之三)
    LeetCode 404. Sum of Left Leaves (左子叶之和)
    LeetCode 257. Binary Tree Paths (二叉树路径)
    LeetCode Questions List (LeetCode 问题列表)- Java Solutions
    LeetCode 561. Array Partition I (数组分隔之一)
  • 原文地址:https://www.cnblogs.com/JSL2018/p/5850451.html
Copyright © 2011-2022 走看看