算法提高 金属采集_树形dp

时间:2023-03-09 00:21:10
算法提高 金属采集_树形dp
算法提高 金属采集  
时间限制:1.0s   内存限制:256.0MB
问题描述

人类在火星上发现了一种新的金属!这些金属分布在一些奇怪的地方,不妨叫它节点好了。一些节点之间有道路相连,所有的节点和道路形成了一棵树。一共有 n 个节点,这些节点被编号为 1~n 。人类将 k 个机器人送上了火星,目的是采集这些金属。这些机器人都被送到了一个指定的着落点, S 号节点。每个机器人在着落之后,必须沿着道路行走。当机器人到达一个节点时,它会采集这个节点蕴藏的所有金属矿。当机器人完成自己的任务之后,可以从任意一个节点返回地球。当然,回到地球的机器人就无法再到火星去了。我们已经提前测量出了每条道路的信息,包括它的两个端点 x 和 y,以及通过这条道路需要花费的能量 w 。我们想花费尽量少的能量采集所有节点的金属,这个任务就交给你了。

输入格式

第一行包含三个整数 n, S 和 k ,分别代表节点个数、着落点编号,和机器人个数。

接下来一共 n-1 行,每行描述一条道路。一行含有三个整数 x, y 和 w ,代表在 x 号节点和 y 号节点之间有一条道路,通过需要花费 w 个单位的能量。所有道路都可以双向通行。

输出格式
输出一个整数,代表采集所有节点的金属所需要的最少能量。
样例输入
6 1 3
1 2 1
2 3 1
2 4 1000
2 5 1000
1 6 1000
样例输出
3004
样例说明

所有机器人在 1 号节点着陆。

第一个机器人的行走路径为 1->6 ,在 6 号节点返回地球,花费能量为1000。

第二个机器人的行走路径为 1->2->3->2->4 ,在 4 号节点返回地球,花费能量为1003。

第一个机器人的行走路径为 1->2->5 ,在 5 号节点返回地球,花费能量为1001。

数据规模与约定

本题有10个测试点。

对于测试点 1~2 , n <= 10 , k <= 5 。

对于测试点 3 , n <= 100000 , k = 1 。

对于测试点 4 , n <= 1000 , k = 2 。

对于测试点 5~6 , n <= 1000 , k <= 10 。

对于测试点 7~10 , n <= 100000 , k <= 10 。

道路的能量 w 均为不超过 1000 的正整数。

解题思路: 

如果没做过树形dp的可以先做poj2342,大体思路跟那个很像,不过一个点可以放多个机器人。

这样每个点就可以有0,1,2,3、、、个机器人了,就有这么多状态。

每个节点储存以这个节点为根的整个树的花费的最少能量。

然后由整棵树的根节点开始,他跟它的子节点有关系,已知需经历过所有的节点。

可以留在子节点0个--k个机器人,当0个的时候也一定要派一个机器人去,所以:

(dp[m][k]表示以m节点为根的树,来k个机器人花费的最少能量)

 dp[root][j]+=dp[tree[root].son[i].to][0]+2*tree[root].son[i].spend;//等于子节点存0个机器人+一个机器人从父节点到子节点,再从子节点到父节点(即2*cost)。
dp[root][j]=min(   dp[root][j],     dp[root][j-l] + dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend      );//但子节点也可能停留0到j个机器人,所以需要循环一遍再来更新dp[root][j]的值。  我这里用min()函数报错呢,就改成if了。。。
第二个dp里面有j-l,l是从0开始的,如果j从0开始,j-l就成负的了,这里要注意j那个循环要从k开始。
 
#include <iostream>
#include <cstdio>
#include <vector>
#include <queue>
#include <map>
#include <cmath>
#include <stack>
#include <cstring>
#include <algorithm>
#include <cstdlib>
#define FOR(i,x,n) for(long i=x;i<n;i++)
#define ll long long int
#define INF 0x3f3f3f3f
#define MOD 1000000007
#define MAX_N 60
#define MAX_M 1005 using namespace std; struct node2{int to;int spend;};
//struct node2 edge; struct node{
int number;
int rating;
vector<node2> son;//编号,花费
int father;
};
node tree[];
int visable[];
int dp[][];//0表示不去,1表示去
int n,S,k; void dfs(int root){
visable[root]=;
FOR(i,,tree[root].son.size()){
if(!visable[tree[root].son[i].to]){
dfs(tree[root].son[i].to);
for(int j=k;j>=;j--){//注意0的时候也要循环
dp[root][j]+=dp[tree[root].son[i].to][]+*tree[root].son[i].spend;
FOR(l,,j+){
if(dp[root][j-l]+dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend<dp[root][j]){
dp[root][j]=dp[root][j-l]+dp[tree[root].son[i].to][l]+l*tree[root].son[i].spend;
}
}
}
} }
} int main()
{
//freopen("input1.txt", "r", stdin);
//freopen("data.out", "w", stdout);
int t1,t2,t3;
scanf("%d %d %d",&n,&S,&k);
memset(visable,,sizeof(visable));
memset(dp,,sizeof(dp));
FOR(i,,n){
scanf("%d %d %d",&t1,&t2,&t3);
node2 t={t2,t3};
node2 tt={t1,t3};
tree[t1].son.push_back(t);
tree[t2].son.push_back(tt);
}
dfs(S);
printf("%d",dp[S][k]);
//fclose(stdin);
//fclose(stdout);
return ;
}