HDOJ 4003 Find Metal Mineral (树DP)

题意:给定一棵树,边权表示通过此边的代价,给k个机器人,指定从点s出发,求遍历所有结点的最小代价和。

分析:设计状态时不难想到用dp[i][j]表示从结点 i 出发遍历以它为根的子树的最小代价,但是转移时就遇到麻烦了,考虑只给你 1 个机器人的时候,这时要遍历所有结点就必然要走回头路,如果我们对每个结点再增加一个信息,表示从 i 出发遍历以 i 为根的子树且最后回到 i 的最小代价,这样转移就好办了,对于每个结点,将 j 个机器人分配给它的所有子结点,若分配 0 个机器人,则表明要派一个机器人去,遍历完了又回到 i 。方便起见,就以dp[i][0]表示从 i 出发遍历完子树 i 又回到i的最小代价。

View Code
#include <stdio.h>
#include <string.h>
#include <algorithm>
using namespace std;
#define N 10010
#define M 11
int n,e,s,m;
int first[N],next[N<<1],v[N<<1],w[N<<1],d[N];
int dp[N][M];
void init()
{
    e=0;
    memset(first,-1,sizeof(first));
    memset(d,0,sizeof(d));
    memset(dp,0,sizeof(dp));
}
void add(int a,int b,int c)
{
    d[a]++;
    v[e]=b;
    w[e]=c;
    next[e]=first[a];
    first[a]=e++;
}
void dfs(int a,int fa)
{
    if(d[a]==1 && v[first[a]]==fa)  return;
    int i,j,k,b;
    for(i=first[a];~i;i=next[i])
    {
        b=v[i];
        if(b==fa)   continue;
        dfs(b,a);
        for(j=m;j>=0;j--)
        {
            dp[a][j]+=dp[b][0]+2*w[i];
            for(k=1;k<=j;k++)
            {
                dp[a][j]=min(dp[a][j],dp[a][j-k]+dp[b][k]+k*w[i]);
            }
        }
    }
}
int main()
{
    int a,b,c;
    while(~scanf("%d%d%d",&n,&s,&m))
    {
        init();
        for(int i=1;i<n;i++)
        {
            scanf("%d%d%d",&a,&b,&c);
            add(a,b,c);
            add(b,a,c);
        }
        dfs(s,0);
        printf("%d\n",dp[s][m]);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/algorithms/p/2689010.html