hdu 4003 Find Metal Mineral (树形dp+分组背包)

题意:求k个机器人从同一点出发遍历整棵树所要的最小花费。树中边有权值。

分析:

1、这是带回溯的树形dp,和apple tree一样。这题是边权,apple tree是点权。

2、很明显是至少有一个机器人遍历整棵树。分给子树遍历的机器人越多,从子树的根回到它的父节点走

的重复路程也越多。“至少有一个”联想到分组背包。

3、dp[i][0]表示1个机器人遍历整棵树,不分给以i为根节点的树的子树另外的机器人。

把总的机器人个数当做背包容积,边权当作价值。

for(int j=V;j>=0;j--)

        for(int k=1;k<=j;k++)

dp[s][j]=min(dp[s][j],dp[s][j-k]+dp[v][k]+edge(s,v)*k);

分k(1<=k<=j)个机器人遍历v为根的子树。

为了保证至少选一个,先把dp[v][0]放入背包。


#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;

int dp[10010][12],head[10010];
int V,tot;

struct node
{
    int to,val;
    int next;
}edge[10010*2];

int minn(int a,int b)
{
    return a<b?a:b;
}

void add(int x,int y,int c)
{
    edge[tot].to=y;
    edge[tot].val=c;
    edge[tot].next=head[x];
    head[x]=tot++;
}

void init()
{
    memset(dp,0,sizeof(dp));
    memset(head,-1,sizeof(head));
    tot=0;
}

void dfs(int u,int pre)
{
    int i;
    for(i=head[u];i!=-1;i=edge[i].next)
    {
        int t=edge[i].to;
        if(t==pre)         //如果t是父亲节点continue;
            continue;
        dfs(t,u);
        for(int j=V;j>=0;j--)
        {
            dp[u][j]+=dp[t][0]+2*edge[i].val;    //保证至少选一个
            for(int k=1;k<=j;k++)
                dp[u][j]=minn(dp[u][j],dp[u][j-k]+dp[t][k]+k*edge[i].val);
        }
    }
}

int main()
{
    int n,s,a,b,cost;
    while(scanf("%d%d%d",&n,&s,&V)!=EOF)
    {
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&cost);
            add(a,b,cost);
            add(b,a,cost);
        }
        dfs(s,-1);
        printf("%d\n",dp[s][V]);
    }
    return 0;
}


hdu 4003 Find Metal Mineral (树形dp+分组背包)

上一篇:CheckedTextView的使用


下一篇:阿里云中间件是什么-阿里云中间件介绍