hdu4003 Find Metal Mineral(树形dp)

src: http://acm.hdu.edu.cn/showproblem.php?pid=4003

思路:dp[u][k]表示遍历完u的子树后,有k个机器人没有回到u。   对于结点u,如果机器人回来的话,派几个都是一样,所以考虑不回来的数量,而k决定了不回来个数的上限,另外 ,机器人最终都会停在叶节点!!!

 

ac代码:

#include <iostream>
#include<stdio.h>
#include<cstdlib>
#include<algorithm>
#include<cmath>
#include<functional>
#include<utility>
#include<string>
#include<string.h>
#include<vector>
#include<iomanip>
#include<stack>
#include<time.h>
using namespace std;
#define FOR(i,a,b) for(int i=a;i<=b;i++)
#define Max(a,b) a=max(a,b)
#define Min(a,b) a=min(a,b)
const int inf=99999999;

int n,s,k,dp[10001][12],Enum=0,head[10001];
struct node
{
    int to,ne,v;
}edge[20010];
void init()
{
    Enum=0;
    memset(head,-1,sizeof(head));
    memset(dp,0,sizeof(dp));
};
void add_edge(int a,int b,int v)
{
    edge[Enum].to=b;
    edge[Enum].v=v;
    edge[Enum].ne=head[a];
    head[a]=Enum++;
}
void dfs(int u,int fa)
{
    for(int i=head[u];i!=-1;i=edge[i].ne){
        int v=edge[i].to;
        if(v==fa)continue;
        dfs(v,u);
        for(int m=k;m>=0;m--){//分组背包
            dp[u][m]+=(dp[v][0]+2*edge[i].v);
            for(int j=1;j<=m;j++){//dp[u][m-j]指的是j个机器人用于子树v,而m-j用于除子树v外的其他子树
                Min(dp[u][m],dp[u][m-j]+dp[v][j]+j*edge[i].v);//注意是j*
            } //这里dp[u][j-k]已经是上个阶段的了,就是只遍历了该父节点的前面的子树的情况!!!
        }
    }
}

int main()
{
    ios::sync_with_stdio(false);
    while(cin>>n>>s>>k){
        init();
        int a,b,c;
        for(int i=1;i<n;i++){
            //cin>>a>>b>>c;
            scanf("%d %d %d",&a,&b,&c);
            add_edge(a,b,c);add_edge(b,a,c);
        }
        dfs(s,-1);
        cout<<dp[s][k]<<endl;
    }
    return 0;
}

 

posted @ 2018-06-06 21:36  WindFreedom  阅读(130)  评论(0)    收藏  举报