hdu4003Find Metal Mineral 树形dp+分组背包

//k个机器人从一颗树的树根开始往下走,
//走树的每条边都要消耗能量,问这k个人最少花多少能量能遍历所有点
//dp[u][i] 表示以u点为根节点的子树用i个节点遍历最少需要多少能量
//当i = 0时表示有一个点遍历了这颗子树又返回上一个节点
#include<cstdio>
#include<cstring>
#include<iostream>
#include<vector>
using namespace std ;
const int maxn = 10010 ;
const int inf = 0x3f3f3f3f;
int dp[maxn][60] ;
int head[maxn] ;
int nedge ;
int n , s , m;
struct Edge
{
    int v , w ;
    int next ;
}edge[maxn<<1] ;
void addedge(int u , int v , int w)
{
    edge[nedge].v = v ;
    edge[nedge].w = w;
    edge[nedge].next = head[u] ;
    head[u] = nedge++;
}
void dfs(int u , int pre)
{
    int flag = 0 ;
    for(int i = head[u] ;i != -1 ;i =edge[i].next)
    {
        int v = edge[i].v ;
        if(v == pre)continue ;
        dfs(v , u) ;
        int len = edge[i].w ;
        for(int j = m;j >= 0;j--)
        {
            int sum = inf ;
            for(int k = 0;k <= j;k++)
            {
                int tmp = (k == 0 ? 2*len : k*len);
                sum = min(sum , dp[u][j-k] + dp[v][k] + tmp) ;
            }
            dp[u][j] = sum;
        }
    }
}
int main()
{
  //freopen("in.txt" ,"r" , stdin) ;
    while(~scanf("%d%d%d" ,&n , &s , &m))
    {
        memset(head , -1 , sizeof(head)) ;
        memset(dp , 0 ,sizeof(dp)) ;
        nedge = 0 ;
        for(int i = 1;i < n;i++)
        {
            int u , v , w ;
            scanf("%d%d%d" , &u , &v , &w) ;
            addedge(u , v , w) ;
            addedge(v , u , w) ;
        }
        dfs(s,0) ;
        cout<<dp[s][m]<<endl;
    }
    return 0 ;
}


你可能感兴趣的:(树形DP,分组背包)