zoukankan      html  css  js  c++  java
  • 【BZOJ1812】[Ioi2005]riv 树形DP

    【BZOJ1812】[Ioi2005]riv

    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

    题解:憋了一上午想出来的树形DP题~

    如何设状态呢?显然n=100,应该是3维的状态,并且有一维是x,有一维是x的子树中建了多少个伐木场,最后一维呢?用y表示x最近的建了伐木场的祖先!

    状态都设完了就做完了~用f[x][y][z]表示x子树中建y个伐木场,并且x的木料运到x的z级祖先的最小花费。那么对于y这一维相当于树形背包。对于z这一维,它的儿子运到的位置一定不会比x的z级祖先更远,那么就用f[x][y][z]和f[x'][y'][z'](x'是x的儿子,z'<=z+1)来更新f'[x][y+y'][z]即可。

    网上的代码怎么都是左儿子右兄弟啊~

    #include <cstdio>
    #include <cstring>
    #include <iostream>
    using namespace std;
    typedef long long ll;
    int n,m,cnt;
    ll ans;
    int to[110],next[110],head[110],fa[110][110],sf[110],siz[110],w[110],v[110],dep[110];
    ll f[110][110][110],g[110][110];
    inline int rd()
    {
    	int ret=0,f=1;	char gc=getchar();
    	while(gc<'0'||gc>'9')	{if(gc=='-')f=-f;	gc=getchar();}
    	while(gc>='0'&&gc<='9')	ret=ret*10+gc-'0',gc=getchar();
    	return ret*f;
    }
    inline void add(int a,int b)
    {
    	to[cnt]=b,next[cnt]=head[a],head[a]=cnt++;
    }
    void dfs(int x)
    {
    	int i,j,k,l,y;
    	fa[x][0]=x,siz[x]=1;
    	for(i=0;i<=sf[x];i++)	y=fa[x][i],f[x][i][!i]=(dep[x]-dep[y])*w[x];
    	for(i=head[x];i!=-1;i=next[i])
    	{
    		y=to[i],dep[y]=dep[x]+v[y];
    		for(j=0;j<=sf[x];j++)	fa[y][++sf[y]]=fa[x][j];
    		dfs(y);
    		memset(g,0x3f,sizeof(g));
    		for(j=0;j<=sf[x];j++)	for(k=min(m,siz[x]);k>=0;k--)	for(l=min(m-k,siz[y]);l>=0;l--)
    			g[j][k+l]=min(g[j][k+l],f[x][j][k]+min(f[y][j+1][l],f[y][0][l]));
    		siz[x]+=siz[y];
    		for(j=0;j<=sf[x];j++)	for(k=0;k<=min(m,siz[x]);k++)	f[x][j][k]=g[j][k];
    	}
    }
    int main()
    {
    	n=rd(),m=rd()+1;
    	memset(head,-1,sizeof(head));
    	int i;
    	for(i=1;i<=n;i++)	w[i]=rd(),add(rd(),i),v[i]=rd();
    	memset(f,0x3f,sizeof(f));
    	dfs(0);
    	printf("%lld",f[0][0][m]);
    	return 0;
    }
  • 相关阅读:
    JS保留小数点(四舍五入、四舍六入)实例
    HTML5 本地存储 localStorage、sessionStorage 的遍历、存储大小限制处理
    TCP/IP 网络编程(五)
    【IOS】mac终端运行.sh文件总是提示permission denied
    一扫天下——ZXing使用全解析
    《学习bash》笔记--进程处理
    VB断点调试
    poj 2506 Tiling(java解法)
    策略模式实战之优惠方式
    HTML 5 音频Audio
  • 原文地址:https://www.cnblogs.com/CQzhangyu/p/7605481.html
Copyright © 2011-2022 走看看