题意:
一棵树边上有花费 在树根上放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; }
HDU 4003 Find Metal Mineral,布布扣,bubuko.com
原文地址:http://blog.csdn.net/houserabbit/article/details/36632427