hdu 4003 Find Metal Mineral 树形DP

题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=4003

题意:有n个矿,矿之间有n-1条路,每条路有相应花费。有k个机器人,从s点出发,求遍历每个矿的最小花费。


对于一个根节点s,如果机器人足够遍历所有的子树,可以看做常规的树状dp,分配c个机器人去遍历子树,求最优解。

如果机器人不够时,那么就从别的子树那里借一些机器人,从根节点出法,遍历结束后返回根节点还给别的子树。那借几个机器人是最优状况?由于每个节点都需要遍历,并且机器人要返回根节点,所以每条路都至少需要走两遍。若借的机器人越多,重复走的路也就越多(树形结构),所以只需要一个机器人。综上可知,当机器人数为0的时候,借一个机器人遍历子树,然后再返回根节点。


#include <iostream>
#include<cstdio>
#include<cstring>
#include<cmath>
#include<vector>
#define N 11000
using namespace std;

struct node
{
    int u,w;
    node(int a,int b):u(a),w(b){}
};
vector<node> r[N];
int d[N][12],v[N],n,s,k;

void dfs(int t)
{
    v[t]=1;
    for(int i=0;i<r[t].size();i++)
    {
        int u=r[t][i].u;
        int w=r[t][i].w;
        if(v[u])   continue;
        dfs(u);
        for(int j=k;j>=0;j--)
        {
            d[t][j]+=d[u][0]+2*w;
            //初始化前i棵子树的最小花费。由于前i-1的情况已求,只需要加上第i棵子树的最坏情况。
            for(int c=1;c<=j;c++)
                d[t][j]=min(d[t][j],d[t][j-c]+d[u][c]+w*c);//派遣c个机器人去子树。
        }
    }
}

int main()
{
    while(~scanf("%d%d%d",&n,&s,&k))
    {
        for(int i=0;i<=n;i++)   r[i].clear();
        for(int i=1;i<n;i++)
        {
            int u,c,w;
            scanf("%d%d%d",&u,&c,&w);
            r[u].push_back(node(c,w));
            r[c].push_back(node(u,w));
        }
        memset(d,0,sizeof(d));
        memset(v,0,sizeof(v));
        dfs(s);
        cout<<d[s][k]<<endl;
    }
}

你可能感兴趣的:(动态规划,HDU,背包问题,树形DP,树状背包)