• 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;
    }
    

      










  • 相关阅读:
    python获取股票数据接口
    Excel使用VBA读取实时WebService股票数据
    安装Pycharm
    Pycharm2019使用
    KLine
    pycharm下用mysql
    新浪股票接口
    SpringBoot整合持久层技术--(二)MyBatis
    SpringBoot整合持久层技术--(一)JdbcTemplate
    SpringBoot整合WEB开发--(十)配置AOP
  • 原文地址:https://www.cnblogs.com/Lazers/p/6632728.html
Copyright © 2020-2023  润新知