其他分享
首页 > 其他分享> > Vjudge-Find Metal Mineral(HDU - 4003)

Vjudge-Find Metal Mineral(HDU - 4003)

作者:互联网

written on 2022-04-13

树形背包题,写一篇题解总结一下

题意:给一棵 \(n\) 个节点的树, 节点编号为1 ~ \(n\) , 每条边都有一个花费值.
有 \(k\) 个机器人从 \(S\) 点出发, 问让机器人遍历所有边,最少花费值多少?

因为树形背包的题确实做得不多,掌握的不是很好,刚开始并没有什么思路。分析一下:

1.题目说从 \(S\) 点出发,因为是无根树,所以以 \(S\) 为根建树,这样可以有效的达到树形dp每一个节点的dp值都只依赖子节点的效果。(显然)

2.然后用dp的方式思考,就是以每个子树为一个研究对象。那么对于这个子树而言,要记录的状态显然有节点编号和下放的机器人数量,即\(dp[x][j]\)表示 \(x\) 这棵子树(不含x)。

3.【然后考虑转移,fa->son派机器人的时候,不同的决策是在son子树里留下0个,1个,…,j个机器人。以上决策互斥,且必须选一个,这就用到了分组背包的思想】。对于一般的状态\(f[x][j]\) 有

for(int l=1;l<=j;l++) f[x][j]=min(f[x][j],f[y][l]+f[x][j-l]+edge*l);

(其实是一个分组背包的模板)

特别的,对于\(f[x][0]\)(下放了然后回来),这时\(fa-son\) 这条边被走了两次,所以要乘二,即

for(int j=k;j>=0;j--) f[x][j]+=f[y][0]+2*z;

总代码

#include<iostream>
#include<cstdio>
#include<cstring>
#include<algorithm>
#define N 10005
using namespace std;
int n,rt,k;
int tot,ver[N<<1],edge[N<<1],nxt[N<<1],head[N];
void add_E(int x,int y,int z){ver[++tot]=y,edge[tot]=z,nxt[tot]=head[x],head[x]=tot;}
int f[N][15];
void dfs(int x,int fa)
{
	for(int i=head[x];i;i=nxt[i])
	{
		int y=ver[i],z=edge[i];
		if(y==fa) continue;
		dfs(y,x);
		for(int j=k;j>=0;j--)
		{
			f[x][j]+=f[y][0]+2*z;//对于每一个儿子,都预先分配一个机器人访问并返回,以获得初始值 
			for(int l=1;l<=j;l++)
				f[x][j]=min(f[x][j],f[y][l]+f[x][j-l]+z*l);
		}
	}
}
/*
f[x][j]表示走完x这棵子树,派出j个机器人(j>0不回来,j==0回来),最少代价是多少 
*/
int main()
{
	while(scanf("%d%d%d",&n,&rt,&k)!=EOF)
	{
		memset(f,0,sizeof(f));
		tot=0;
		memset(head,0,sizeof(head));
		for(int i=1;i<n;i++)
		{
			int x,y,z;
			scanf("%d%d%d",&x,&y,&z);
			add_E(x,y,z),add_E(y,x,z);
		}
		dfs(rt,0);
		printf("%d\n",f[rt][k]);
	}
}

思路参考以及【引用】来源于引用

不懂再看看把它弄懂

标签:HDU,Mineral,int,Vjudge,机器人,son,include,节点,dp
来源: https://www.cnblogs.com/Freshair-qprt/p/16537682.html