hdu 4003 Find Metal Mineral 树形DP

来源:互联网 发布:php include path 编辑:程序博客网 时间:2024/04/20 06:26

题目链接: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 11000using 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;    }}

1 0
原创粉丝点击