题意:
一棵树边上有花费 在树根上放man个机器人 问 在每个节点至少一个机器人经过的前提下 最少花费多少
思路:
树形dp
dp[u][j] 表示j个机器人遍历以u为根的子树的最少花费
dp[u][0] 表示只用一个机器人遍历u的子树并回到u的花费(即子树中所有边权和乘2)
状态转移 dp[u][j] = min ( dp[u][j-k] + dp[v][k] + ed.w * k ) 其中v是u的儿子
理解一下就是 扫描到v这个儿子时 让k个机器人去遍历v的子树 其他j-k个负责遍历u的子树(此时u的子树指的是u的子树中扫描到v节点前的部分) 因为要k个机器人走到v 所以边权ed.w要乘k
代码:
#include<cstdio>
#include<cstring>
#include<algorithm>
using namespace std;
#define N 10010
struct edge
{
int v,w,next;
}ed[N*2];
int head[N],dp[N][15];
int tot,n,root,man;
void add(int u,int v,int w)
{
ed[tot].v=v;
ed[tot].w=w;
ed[tot].next=head[u];
head[u]=tot++;
}
void dfs(int u,int fa)
{
int i,j,k,v;
for(i=head[u];~i;i=ed[i].next)
{
v=ed[i].v;
if(v==fa) continue;
dfs(v,u);
for(j=man;j>=0;j--)
{
dp[u][j]+=dp[v][0]+ed[i].w*2; //最差情况无非是只让一个机器人去遍历v子树再回到u
for(k=1;k<=j;k++)
{
dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+ed[i].w*k);
}
}
}
}
int main()
{
int i,u,v,w;
while(~scanf("%d%d%d",&n,&root,&man))
{
tot=0;
memset(head,-1,sizeof(head));
memset(dp,0,sizeof(dp));
for(i=1;i<n;i++)
{
scanf("%d%d%d",&u,&v,&w);
add(u,v,w);
add(v,u,w);
}
dfs(root,-1);
printf("%d\n",dp[root][man]);
}
return 0;
}