hdu 4003

题意:给你m个机器人从s点出发,,每条路由一定的权值,求历遍整棵树最小的权值。

显然是树dp,但是我不会,这是我第一题树dp,看着题解写的,刚开始有点难懂,但是自己画画,自己想想怎么样由子树转移,然后就能看懂别人的程序了,组要难点是那个类似背包的递推,其实是这样的,每一颗子树相当于一个物品i,但是容量k(机器人数)可以任选,将它放进总容量中,使得这个总容量j的权值最优,然后由第一颗子树推到最后,跟背包一样,由前i个物品的最优和当前的物品匹配选最优,我们知道01背包能化为1维的,这里也是这样优化的。。。

参考http://blog.youkuaiyun.com/ahero_happy/article/details/6747116

我代码有点点不一样,注释可以看看他的

Run IDSubmit TimeJudge StatusPro.IDExe.TimeExe.MemoryCode Len.LanguageAuthor
46090662011-09-15 23:22:24Accepted4003718MS1516K1265BG++xym2010
#include<cstdio>
#include<cstring>
#include<string>
#include<iostream>
#include<algorithm>
#include<cmath>
#define LL long long
using namespace std;
struct egde
{
	int v,w,next;
}e[20020];
int fa[10020],n,s,m,pos;
LL dp[10020][12];
void DP(int t,int p)
{
	for(int i=fa[t];i!=-1;i=e[i].next)
	{
		if(e[i].v==p)continue;
		DP(e[i].v,t);
	}
	for(int i=fa[t];i!=-1;i=e[i].next)
	{
		if(e[i].v==p)continue;
		int tem=e[i].v;
		for(int j=10;j>=0;j--)
		{

			if(dp[t][j]==0)
			{   
				if(j==0)dp[t][0]=dp[tem][0]+2*e[i].w;
				else
					for(int k=1;k<=j;k++)
					{
						if(dp[t][j]==0||dp[t][j]>dp[tem][k]+k*e[i].w)
							dp[t][j]=dp[tem][k]+k*e[i].w;
					}
			}
			else
			{
				dp[t][j]+=2*e[i].w+dp[tem][0];
				for(int k=1;k<=j;k++)
				{
					dp[t][j]=min(dp[t][j],dp[t][j-k]+dp[tem][k]+k*e[i].w);
				}
			}
		}
	}
}
int main()
{
	int x,y,w;
	while(scanf("%d%d%d",&n,&s,&m)!=EOF)
	{
		pos=0;
		memset(fa,-1,sizeof(fa));
		for(int i=0;i<n-1;i++)
		{
			scanf("%d%d%d",&x,&y,&w);
			e[pos].v=y;e[pos].w=w;e[pos].next=fa[x];fa[x]=pos++;
			e[pos].v=x;e[pos].w=w;e[pos].next=fa[y];fa[y]=pos++;
		}
		memset(dp,0,sizeof(dp));
		DP(s,-1);
		cout<<dp[s][m]<<'\n';
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值