首页 > 代码库 > HDU 4003 Find Metal Mineral

HDU 4003 Find Metal Mineral

题意:

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