zoukankan      html  css  js  c++  java
  • 1812: [Ioi2005]riv

    1812: [Ioi2005]riv

    Time Limit: 10 Sec Memory Limit: 64 MB
    Submit: 635 Solved: 388
    [Submit][Status][Discuss]

    Description

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

    Input

    第一行 包括两个数 n(2<=n<=100),k(1<=k<=50,且 k<=n)。n为村庄数,k为要建的伐木场的数目。除了bytetown外,每个村子依次被命名为1,2,3……n,bytetown被命名为0。 接下来n行,每行包涵3个整数 wi——每年i村子产的木料的块数 (0<=wi<=10000) vi——离i村子下游最近的村子(或bytetown)(0<=vi<=n) di——vi到i的距离(km)。(1<=di<=10000) 保证每年所有的木料流到bytetown的运费不超过2000,000,000分 50%的数据中n不超过20。

    Output

    输出最小花费,精确到分。

    Sample Input

    4 2
    1 0 1
    1 1 10
    10 2 5
    1 2 3

    Sample Output

    4

    HINT

    Source

    [Submit][Status][Discuss]


    万恶的树形dp,写了一下午QAQ

    • 如果有一道题是wzx没有做过的,唯一可能是他并不想做

    嘤嘤嘤

    二位状态不太合理,要建三维
    (f[i][j][k])表示在(i)的子树中一共建了k个伐木场,其中没有到伐木场的木头需要运到(j)级祖先
    主要是难转移啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊啊


    #include<iostream>
    #include<cstdio>
    #include<cstring>
    #include<algorithm>
    #include<cmath>
    #define max(a,b) ((a)>(b) ? (a): (b))
    #define min(a,b) ((a)<(b) ? (a): (b))
    #define LL long long
    #define M 999999999999
    #define RI register int 
    using namespace std;
    
    int i,m,n,j,k,a[101],d[101],ver[101],edge[101],head[101],nex[101],w[101],v,g,cnt,s[101];
    LL f[101][101][101];
    inline void add(int x,int y,int z)
    {
        cnt+=1; ver[cnt]=y; nex[cnt]=head[x]; head[x]=cnt; edge[cnt]=z;
    }
    
    void dfs(int now,int de)
    {
        s[now]=1;
        for(RI i=head[now];i;i=nex[i])
        {
            int t=ver[i];
            d[de+1]=edge[i]+d[de];
            dfs(t,de+1);
            s[now]+=s[t];
            for(RI j=0;j<=de;j++)
                for(RI l=s[now];l>=0;l--) 
                {
                    LL x=M;
                    for(RI z=l;z>=0;z--) x=(LL)min(x,min(f[now][j][l-z]+f[t][0][z],f[now][j][l-z]+f[t][j+1][z])); 
                    f[now][j][l]=x;
                }
        }
    
        for(RI i=1;i<=de;i++) 
            for(RI j=0;j<=s[now]-1;j++) f[now][i][j]+=(LL)(d[de]-d[de-i])*w[now];
        for(RI i=k+1;i;i--) f[now][0][i]=(LL)f[now][0][i-1];
        f[now][0][0]=M;
    }
    
    int main()
    {
        scanf("%d%d",&n,&k);
        for(RI i=1;i<=n;i++)
        {
            scanf("%d%d%d",&w[i],&v,&g);
            add(v,i,g);
        }
        dfs(0,0);
        printf("%lld",f[0][0][k+1]);
    }
    
  • 相关阅读:
    创建对象的七种方式
    设计模式之工厂模式
    设计模式之单例模式
    排序算法之插入排序
    排序算法之选择排序
    类及对象初体验
    排序算法之冒泡排序
    迭代器和生成器
    装饰器
    函数进阶
  • 原文地址:https://www.cnblogs.com/ZUTTER/p/9794999.html
Copyright © 2011-2022 走看看