HDU-4003 Find Metal Mineral (树形DP+分组背包)

题目大意:用m个机器人去遍历有n个节点的有根树,边权代表一个机器人通过这条边的代价,求最小代价。

题目分析:定义状态dp(root,k)表示最终遍历完成后以root为根节点的子树中有k个机器人时产生的总代价。则状态转移方程为:

dp(root,k)=min(dp(root,k),dp(son,j)+dp(root,k-j)+j*w(root,son))  j>0

要注意,当j为0的时候表示遍历完son这个子树后所有的机器人都回到root。可以证明,如果让遍历son的所有的机器人都回到root,那么遍历son的机器人越多,产生的代价就越高。

 

代码如下:

# include<iostream>
# include<cstdio>
# include<cstring>
# include<algorithm>
using namespace std;
# define LL long long

const int N=10005;

struct Edge
{
	int to,w,nxt;
};
Edge e[N<<1];

int head[N];
int cnt,n,s,m;
int dp[N][12];

void add(int u,int v,int w)
{
	e[cnt].to=v;
	e[cnt].w=w;
	e[cnt].nxt=head[u];
	head[u]=cnt++;
}

void init()
{
	int a,b,w;
	cnt=0;
	memset(dp,0,sizeof(dp));
	memset(head,-1,sizeof(head));
	for(int i=1;i<n;++i){
		scanf("%d%d%d",&a,&b,&w);
		add(a,b,w);
		add(b,a,w);
	}
}

void dfs(int u,int fa)
{
	for(int i=head[u];i!=-1;i=e[i].nxt){
		int v=e[i].to;
		if(v==fa) continue;
		dfs(v,u);
		for(int j=m;j>=0;--j){
			dp[u][j]+=dp[v][0]+2*e[i].w;
			for(int k=1;k<=j;++k)
				dp[u][j]=min(dp[u][j],dp[u][j-k]+dp[v][k]+k*e[i].w);
		}
	}
}

void solve()
{
	dfs(s,-1);
	printf("%d\n",dp[s][m]);
}

int main()
{
	while(~scanf("%d%d%d",&n,&s,&m))
	{
		init();
		solve();
	}
	return 0;
}

  

posted @ 2016-04-04 09:07  20143605  阅读(348)  评论(0编辑  收藏  举报