HDU 4003:Find Metal Mineral 树形DP+分组背包 Find Metal Mineral
题目链接:
http://acm.hdu.edu.cn/showproblem.php?pid=4003
题意:
有一棵树(存在N个节点),树上每条边都有权值,在其根节点S上有K个机器人,求这些机器人遍历所有点所花费的最小权值和
题解:
设dp[i][j]为以i为根节点的子树上有X个机器人的最小花费,按分组背包的思想跑一遍DP就好了,注意每个节点上j为0的情况
代码
#include<stdio.h>
#include<string.h>
#include<vector>
using namespace std;
const int maxn=10001;
int dp[maxn][11];//以i为根节点的子树上有X个机器人的最小花费
bool mark[maxn];
int mmin(int x,int y)
{
return x<y?x:y;
}
int mmax(int x,int y)
{
return x>y?x:y;
}
struct node
{
int to,cost;
node(int x=0,int y=0)
{
to=x,cost=y;
}
};
vector<node>q[maxn];
int m,sum[maxn];
void Dfs(int id)
{
mark[id]=true;
for(int i=0;i<q[id].size();++i)
{
int v=q[id][i].to;
if(mark[v])continue;
int cost=q[id][i].cost;
Dfs(v);
for(int j=m;j>=1;--j)
{
dp[id][j]+=cost*2+dp[v][0];
for(int k=0;k<=j;++k)
{
if(k)dp[id][j]=mmin(dp[id][j],dp[id][j-k]+dp[v][k]+cost*k);
else dp[id][j]=mmin(dp[id][j],dp[id][j-k]+dp[v][k]+cost*2);//k为0需要往回跑
}
}
dp[id][0]+=cost*2+dp[v][0];
}
}
int main()
{
int N,S,K,a,b,c;
while(~scanf("%d%d%d",&N,&S,&K))
{
m=K;
for(int i=1;i<=N;++i)
q[i].clear();
memset(dp,0,sizeof(dp));
memset(mark,false,sizeof(mark));
for(int i=1;i<N;++i)
{
scanf("%d%d%d",&a,&b,&c);
q[a].push_back(node(b,c));
q[b].push_back(node(a,c));
}
Dfs(S);
printf("%d
",dp[S][K]);
}
}