/*
题目类型:
树形DP
题意:
是求k个机器人从S 点开始历遍所有节点的最小代价。
原理:
1)对于每一个节点, 分别求出当前节点有x(x <= K && x > = 0)个机器人进行历遍时的最小代价(这x个机器人会留在该分支)。
2)当有机器人留在这个节点下的分支时,则不会有让任何机器人从该节点出来。因为出来机器人的所历遍的节点或分支完全可以由留在这个节点的机器人来历遍,而且所花费的代价还要小。所以对于机器人为0的节点,其实是派了一个机器人进行历遍然后又回来。
题外话:
这道题思路还是挺简单的,只是一开始的时候对于花费和效率的平衡处理的不是很还好,结果不是超时就是超空间。最后才解决,稀疏表的访问处理(其实是看了大牛们写的代码= =)
*/
#include <cstdio>
#include <cstring>
#include <cstdlib>
using namespace std;
struct Piont {
int x, y, w, next;
};
int tree[10001][11];
Piont map[20001];
int N, S, K, former[10001]; //fromer[x] 代表的是x点之前所链接的边的编号。
void SetMap(int id, int x, int y, int w) {
map[id].x = x;
map[id].y = y;
map[id].w = w;
map[id].next = former[x]; //保存之前的编号
former[x] = id; //更新编号
id += N;
map[id].y = x;
map[id].x = y;
map[id].w = w;
map[id].next = former[y];
former[y] = id;
}
int FindNext(int id) {
int mid = former[id];
if(mid == 0) {
return 0;
}
former[id] = map[mid].next;
return mid;
}
void into(int id, int fid) {
int i;
while(1) {
int mid = FindNext(id);
if(mid == 0) {
break;
}
i = map[mid].y;
if(i == fid) {
continue;
}
int len = map[mid].w;
into(map[mid].y, id);
int j;
for(j = K; j >= 0; j--) {
int cmin = tree[id][j] + len * 2 + tree[i][0];
for(int w = 0; w <= j; w++) {
int a = tree[id][j - w] +len * w + tree[i][w];
if(w == 0) {
a += len * 2;
}
cmin = min(cmin, a);
}
tree[id][j] = cmin;
}
}
}
int main () {
//freopen("Input", "r", stdin);
while (scanf("%d %d %d", &N, &S, &K) != EOF) {
memset(tree, 0, sizeof(tree));
memset(map, 0, sizeof(map));
memset(former, 0, sizeof(former));
int i;
for (i = 1; i < N; i++) {
int x, y, w;
scanf("%d %d %d", &x, &y, &w);
SetMap(i, x, y, w);
}
into(S, 0);
int ans = tree[S][0];
for(i = 1; i <= K; i++) {
ans = min(ans, tree[S][i]);
}
printf("%d\n", ans);
}
return 0;
}
Find Metal Mineral
最新推荐文章于 2020-12-17 13:50:11 发布