Description
在山上一共有N个站点需要检查,检查员从山顶出发去各个站点进行检查,各个站点间有且仅有一条通路,检查员下山前往站点时比较轻松,而上山时却需要额外的时间,问最后检查员检查完所有站点时所需要的额外时间最少是多少。
Input
包含多组数据 每组数据输入第一行为一个整数N 表示站点个数(1<=N<=100000),接下去N-1 行 每行3个整数 x,y,z(1<=z<=10000) 检查站x为检查站y的父节点,x,y之间有一条通路,从y到x需要额外z的时间。(父节点在子节点上方,山顶固定标号为1)
Output
输出一行一个整数表示最少需要花费的额外时间。
Sample Input
6
1 2 1
2 4 1
1 3 1
3 5 1
3 6 1
Sample Output
3
题目乍一看像旅行商问题,但是n这么大,显然不是这么玩的。
考虑到树形结构的特殊性,就是从左子树到右子树,一定要进过父节点才能到达,这点是跟图不一样的。
于是从过程来看,我如果设p[i]表示遍历以i为根的子树所需的最小花费。all[i]表示遍历完并回到i结点的最小花费。当然,起始都是从i结点出发。
那么对于i来说,all[i] = sum(all[k]+dis[k][i])(k是i的子节点)
p[i] = min(sum(all[k]+dis[k][i])+p[j])(其中k != j)
这样的话,用记忆化搜索,便可以得到所有的p和all。p[1]即为所要求。
复杂度是O(n)
但是直接从结果上来看的话,整个遍历的路径,一定是每个线段都一上一下各一次,但是有一条从根部到底部的路径只下不上。(这个从之前的特殊性前提也可以推来)
这样便只需要找这样一条耗费最大的路径,然后用所有路径的和减去它即可。
复杂度也是O(n),但是可以省掉两个数组。
代码:(dp)
#include <iostream> #include <cstdio> #include <cstdlib> #include <cstring> #include <cmath> #include <set> #include <map> #include <queue> #include <string> #include <algorithm> #define LL long long using namespace std; const int maxN = 1e5+5; int n; LL all[maxN], p[maxN]; inline LL myMin(LL x, LL y) { if (x == -1) return y; else return x < y ? x : y; } //链式前向星 struct Edge { int to, next; int val; }edge[maxN]; int head[maxN], cnt; void addEdge(int u, int v, int val) { edge[cnt].to = v; edge[cnt].val = val; edge[cnt].next = head[u]; head[u] = cnt; cnt++; } void initEdge() { memset(head, -1, sizeof(head)); cnt = 0; } void input() { initEdge(); memset(all, -1, sizeof(all)); memset(p, -1, sizeof(p)); int x, y, z; for (int i = 1; i < n; ++i) { scanf("%d%d%d", &x, &y, &z); addEdge(x, y, z); } } void dfs(int now) { LL s = 0; int to; for (int k = head[now]; k != -1; k = edge[k].next) { to = edge[k].to; if (all[to] == -1) dfs(to); s += all[to]+edge[k].val; } all[now] = s; for (int k = head[now]; k != -1; k = edge[k].next) { to = edge[k].to; p[now] = myMin(p[now], s-all[to]-edge[k].val+p[to]); } if (p[now] == -1) p[now] = 0; } void work() { dfs(1); printf("%I64d ", p[1]); } int main() { //freopen("test.in", "r", stdin); while (scanf("%d", &n) != EOF) { input(); work(); } return 0; }