HDU4003 Find Metal Mineral(树形DP+分组背包)

来源:互联网 发布:百度seo干货 编辑:程序博客网 时间:2024/03/29 07:29

Find Metal Mineral

Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65768/65768 K (Java/Others)
Total Submission(s): 3163    Accepted Submission(s): 1460


Problem Description
Humans have discovered a kind of new metal mineral on Mars which are distributed in point‐like with paths connecting each of them which formed a tree. Now Humans launches k robots on Mars to collect them, and due to the unknown reasons, the landing site S of all robots is identified in advanced, in other word, all robot should start their job at point S. Each robot can return to Earth anywhere, and of course they cannot go back to Mars. We have research the information of all paths on Mars, including its two endpoints x, y and energy cost w. To reduce the total energy cost, we should make a optimal plan which cost minimal energy cost.
 

Input
There are multiple cases in the input.
In each case:
The first line specifies three integers N, S, K specifying the numbers of metal mineral, landing site and the number of robots.
The next n‐1 lines will give three integers x, y, w in each line specifying there is a path connected point x and y which should cost w.
1<=N<=10000, 1<=S<=N, 1<=k<=10, 1<=x, y<=N, 1<=w<=10000.
 

Output
For each cases output one line with the minimal energy cost.
 

Sample Input
3 1 11 2 11 3 13 1 21 2 11 3 1
 

Sample Output
32
Hint
In the first case: 1->2->1->3 the cost is 3;In the second case: 1->2; 1->3 the cost is 2;
 

Source
The 36th ACM/ICPC Asia Regional Dalian Site —— Online Contest
题意:一共N个点,N-1条边,K个机器人从S点开始访问其他点,每个机器人经过边(u,v),消耗能量cost(u,v),一条边可以走多遍,问访问所有的点能量最小消耗多少。
思路:
看别人的思路之后写出来的,写得不好还请指出。
所谓的分组背包,就是N件物品和一个大小为V的背包,第i件物品都有它的费用从c[i]和价值w[i],这些物品被划分为若干个组,每组的物品互相冲突,最多只能选一件。
求解将哪些物品装进背包可使得费用不超过背包容量,并且价值总和最大。
假设dp[k][v]表示物品花费v能取得的最大价值,那么状态转移式为:
dp[k][v] = max(dp[k-1][v-c[i]]+w[i])。

再看看这道题,当士兵数量少于叶子数时是需要往回走的,但是选哪条路返回不清楚,但可以知道的是当分配j个机器人到第i个结点的时候,这j个机器人是不能再回到第i个结点
的父结点,因为,这样就多走了i的父亲到i的这条路,完全是不必要的。
那么对于以i结点为根节点的子树,可不可以看做重量最多为k的背包(k为分配给i结点的机器人数),j个儿子看作为j组背包,每组物品的价值都是dp[son][0]、dp[son][1]、dp[son][2]....dp[son][k],物品重量是0,1,2......k。求解在重量不超过k的情况下能获得的最小价值,前提是每个儿子至少要分配一个儿子。那么类似的,当为i结点的前j个儿子分配p个机器人时,要知道前j-1个儿子分配k-p个机器人能获得的最小价值(最小花费)。
对于返回时选择哪条路径返回:
对于i为根节点的儿子,都预先分配一个机器人访问并返回,花费2*cost(fa, son),然后再用分组背包。
假设数据
3 1 1
1 2 2
1 3 1
这样先访问2儿子时,不分配机器人时(即默认一个机器人往返走,可看作没有分配),花费4,分配1个机器人时(只进不出),花费2
访问3儿子时,不分配机器人(即默认一个机器人往返走,最后去到2儿子),总花费4。分配一个机器人时(2儿子往返走),总花费5。
dp时,会根据先前合适的状态下再转移。
那么dp[1][1] = 3。
dp[i][j]表示以第i个结点为根节点,分配j个机器人的最小花费。
#include <stdio.h>#include <string.h>#include <algorithm>#define maxn 10005using namespace std;int dp[maxn][15], head[maxn];struct Edge{    int to, cost, next;}edge[maxn*2];int N, K, S, tot;void add(int u, int v, int cost){    edge[tot].to = v;    edge[tot].cost = cost;    edge[tot].next = head[u];    head[u] = tot++;}void dfs(int fa, int pre){    int i, j, k, son;    for(i = head[fa];i != -1;i = edge[i].next){        int son = edge[i].to;        if(son == pre) continue;        dfs(son, fa);        for(j = K;j >= 0;j--){            dp[fa][j] += dp[son][0]+2*edge[i].cost;            for(k = 1;k <= j;k++)                dp[fa][j] = min(dp[fa][j], dp[fa][j-k]+dp[son][k]+k*edge[i].cost);        }    }}int main(){    int u, v, cost, i, j;    while(~scanf("%d %d %d", &N, &S, &K)){        memset(dp, 0 ,sizeof dp);        memset(head, -1, sizeof head);        tot = 1;        for(i = 0;i < N-1;i++){            scanf("%d %d %d", &u, &v, &cost);            add(u, v, cost);            add(v, u, cost);        }        dfs(S, 0);        printf("%d\n", dp[S][K]);    }}

0 0
原创粉丝点击