zoukankan      html  css  js  c++  java
  • jzoj p1306 河流

    题目描述

    几乎整个Byteland王国都被森林和河流所覆盖。小点的河汇聚到一起,形成了稍大点的河。就这样,所有的河水都汇聚并流进了一条大河,最后这条大河流进了大海。这条大河的入海口处有一个村庄——名叫Bytetown。

    在Byteland国,有n个伐木的村庄,这些村庄都座落在河边。目前在Bytetown,有一个巨大的伐木场,它处理着全国砍下的所有木料。木料被砍下后,顺着河流而被运到Bytetown的伐木场。Byteland的国王决定,为了减少运输木料的费用,再额外地建造k个伐木场。这k个伐木场将被建在其他村庄里。这些伐木场建造后,木料就不用都被送到Bytetown了,它们可以在运输过程中第一个碰到的新伐木场被处理。显然,如果伐木场座落的那个村子就不用再付运送木料的费用了。它们可以直接被本村的伐木场处理。

    注:所有的河流都不会分叉,形成一棵树,根结点是Bytetown。

    国王的大臣计算出了每个村子每年要产多少木料,你的任务是决定在哪些村子建设伐木场能获得最小的运费。其中运费的计算方法为:每一吨木料每千米1分钱。

    输入输出格式

    输入格式:

    第一行包括两个数 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村子下游最近的村子(即i村子的父结点)(0≤vi≤n)

    di——vi到i的距离(千米)。(1≤di≤10000)

    保证每年所有的木料流到bytetown的运费不超过2,000,000,000分

    50%的数据中n不超过20。

    输出格式:

    输出最小花费,单位为分。

    输入输出样例

    输入样例#1:
    4 2
    1 0 1
    1 1 10
    10 2 5
    1 2 3
    输出样例#1:
    4
    ps;题面沾了落谷的;



    一个不错的树形dp题
    由题意来看 这是一颗树
    我们可以将节点和可支配伐木场数作为状态,再对每一节点的子节点分配伐木场数即可;
    但这样显然是不行的,先不谈时间的问题,单是“对每一节点分配伐木场数”这一要求就难以利用代码实现(焫鷄认为)
    所以我们秉承着复杂问题简单化的思想 把他化简为一个左儿子右兄弟的二叉树,这样我们对于每一个节点,只需分配两个子节点即可;
    这样提交上去,只能拿到30分,时间大大超时。
    那我们就应该考虑一下该如何优化了。
    首先对于dp问题我们必须是要用到记忆化搜索的(或是状态转移方程),但是如果单单的记录节点和伐木数这两种状态也是很复杂的,因为对于一个点来说,他拥有的伐木数确定并不意味着这个点是唯一的,因为之前的伐木数分配我们并不清楚,所以我们决定再加上一个状态,即之前的伐木数分配。但其实我们并不需要记录之前所有的分配,只需记录与该点有关的即可,也就是离该点最近的那个伐木场的位置,有了这三个状态,程序的效率就会高上许多,但这个脏题是真的脏,这还是不掉,只能拿到50分。
    我们继续思考,为什么会超时,经过思考之后发现,由于程序分配伐木场数是枚举的,所以可能会出现以下情况: 该点之下的点只剩下n个,而可用的伐木场数k>n;
    在这种情况下,我们不必继续搜索,直接返回0即可,加上这个优化,就终于能拿到这不容易的AC了

    /*
    jzoj	1306 
    2017  3  27 ;
    by century
    */
    #include<iostream>
    #include<string>
    #include<cstring>
    #include<cstdio>
    #include<algorithm>
    using namespace std;
    int dis[100000];
    int w[100000];
    int v[100000];
    int a[1000][1000];
    int top[10000];
    int child[1000000];
    int brother[1000000];
    int n,k;
    int f[200][200][200];
    int ppp[10000];
    int diss(int x,int dix,int father)
    {
    	dis[x]=dix;
    	for(int i=1;i<=n;i++)
    	{
    		if(a[x][i]!=-1)
    		{
    			if(i!=father)
    			ppp[x]+=diss(i,dix+a[x][i],x);
    		}
    	}
    	return ppp[x]+1;
    }
    int vvv(int x)
    {
    	if(x==-1)return 0;
    	ppp[x]=vvv(child[x])+vvv(brother[x]);
    	return ppp[x]+1;
    }
    int dfs(int x,int str,int num,int k)
    {
    	if(x==-1)return 0;
    	if(f[x][num][str])return f[x][num][str];
    	if(num>ppp[x])return 0;
    	int ans=-1;
    	//x不选
    	for(int i=0;i<=num;i++)
    	{
    		if(ans==-1||ans>dfs(child[x],str,i,k+1)+dfs(brother[x],str,num-i,k+1))
    		ans=dfs(child[x],str,i,k+1)+dfs(brother[x],str,num-i,k+1);	
    	}
    	if(ans==-1)
    	ans=w[x]*(dis[x]-dis[str]);
    	else ans+=w[x]*(dis[x]-dis[str]);
    	if(num>0&&x!=0)//x选
    	{
    		int sum=-1;
    		int kk=num-1;
    		for(int i=0;i<=kk;i++)
    		{
    			if(sum==-1||dfs(child[x],x,i,k+1)+dfs(brother[x],str,kk-i,k+1)<sum)
    				sum=dfs(child[x],x,i,k+1)+dfs(brother[x],str,kk-i,k+1);
    		}
    		if(sum==-1)sum=0;
    		return f[x][num][str]=min(ans,sum);
    	}
    	return f[x][num][str]=ans;
    }
    int main()
    {
    	memset(a,-1,sizeof(a));
    	memset(child,-1,sizeof(child));
    	memset(brother,-1,sizeof(brother));
    	cin>>n>>k;
    	for(int i=1;i<=n;i++)
    	{
    		int vv;
    		cin>>w[i]>>vv>>v[i];
    		a[i][vv]=v[i];
    		a[vv][i]=v[i];
    		brother[i]=child[vv];
    		child[vv]=i;
    	}
    	diss(0,0,-1);
    	vvv(0);
    	cout<<dfs(0,0,k,0)<<endl;
    	return 0;
    }
    

      










  • 相关阅读:
    Spring spEL
    Spring 使用外部部署文件
    Spring 自动装配
    spring 属性配置细节
    hdu 1054 Strategic Game
    fzu 2037 Maximum Value Problem
    将博客搬至CSDN
    HDU 4714 Tree2Cycle
    HDU 1009 The Shortest Path in Nya Graph
    POJ 1942 Paths on a Grid 组合数的优化
  • 原文地址:https://www.cnblogs.com/Lazers/p/6632728.html
Copyright © 2011-2022 走看看