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.
解题思路:经典树形DP。这道题的在进行状态转移的时候需要用到贪心的思想,想到这两个贪心的地方,状态转移便好写,如果想不到,状态转移就不好搞了。(1)对于当前子树根节点u,如果我们分配给其x个机器人(x>1)且这x个机器人在遍历完子树之后全部返回到根节点的花费肯定大于等于只有1个机器人遍历这棵子树然后返回到根节点。(2)如果我们分配给其x个机器人且我们只让其中的y个机器人返回,则这种方案的花费是大于等于我们让(x-y)个机器人遍历这棵子树且不返回到根节点的花费的。这两个贪心的地方搞明白了,则我们的状态转移便好写了,设dp[u][i]表示给根节点u分配i个机器人遍历完整棵子树需要的最少花费,则对于当前u的一个子节点v,我们采用的方案由贪心规则可知是只存在两种情况的即(1)让一个节点去遍历整棵子树遍历完之后返回到根节点(2)给该子树分配x个机器人去遍历且不返回到根节点。这样我们便可以轻松地写出树形DP的代码。
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <string>
#include <vector>
#include <deque>
#include <queue>
#include <stack>
#include <map>
#include <set>
#include <algorithm>
#include <functional>
using namespace std;
const int maxn = 10010;
typedef long long ll;
int N, S, K;
struct Edge {
int v, w, next;
Edge() { }
Edge(int _v, int _w, int _next) : v(_v), w(_w), next(_next) { }
}edges[2*maxn];
int head[maxn], edge_sum;
void init_graph() {
edge_sum = 0;
memset(head, -1, sizeof(head));
}
void add_edge(int u, int v, int w) {
edges[edge_sum].v = v;
edges[edge_sum].w = w;
edges[edge_sum].next = head[u];
head[u] = edge_sum++;
edges[edge_sum].v = u;
edges[edge_sum].w = w;
edges[edge_sum].next = head[v];
head[v] = edge_sum++;
}
ll dp[maxn][12];
void dfs(int u, int fa) {
for(int i = head[u]; i != -1; i = edges[i].next) {
int v = edges[i].v;
int w = edges[i].w;
if(v == fa) continue;
dfs(v, u);
for(int j = K; j >= 1; --j) {
dp[u][j] += (dp[v][0] + 2 * w);
for(int k = 1; k <= j; ++k) {
//printf("Test: %I64d %I64d %I64d\n", dp[u][j], dp[u][j-k], dp[v][k] + k * w);
dp[u][j] = min(dp[u][j], dp[u][j-k] + dp[v][k] + k * w);
}
}
dp[u][0] += (dp[v][0] + 2 * w);
}
return ;
}
int main() {
//freopen("aa.in", "r", stdin);
int u, v, w;
while(scanf("%d %d %d", &N, &S, &K) != EOF) {
init_graph();
memset(dp, 0, sizeof(dp));
for(int i = 1; i < N; ++i) {
scanf("%d %d %d", &u, &v, &w);
add_edge(u, v, w);
}
dfs(S, -1);
printf("%I64d\n", dp[S][K]);
}
return 0;
}