HDU 4003 Find Metal Mineral

来源:互联网 发布:淘宝pc链接转换 编辑:程序博客网 时间:2024/05/11 19:37

题意:

一棵树边上有花费  在树根上放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 10010struct 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;}


0 0
原创粉丝点击