题意:给你m个机器人从s点出发,,每条路由一定的权值,求历遍整棵树最小的权值。
显然是树dp,但是我不会,这是我第一题树dp,看着题解写的,刚开始有点难懂,但是自己画画,自己想想怎么样由子树转移,然后就能看懂别人的程序了,组要难点是那个类似背包的递推,其实是这样的,每一颗子树相当于一个物品i,但是容量k(机器人数)可以任选,将它放进总容量中,使得这个总容量j的权值最优,然后由第一颗子树推到最后,跟背包一样,由前i个物品的最优和当前的物品匹配选最优,我们知道01背包能化为1维的,这里也是这样优化的。。。
参考http://blog.youkuaiyun.com/ahero_happy/article/details/6747116
我代码有点点不一样,注释可以看看他的
Run ID | Submit Time | Judge Status | Pro.ID | Exe.Time | Exe.Memory | Code Len. | Language | Author |
4609066 | 2011-09-15 23:22:24 | Accepted | 4003 | 718MS | 1516K | 1265B | G++ | 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;
}