[KOJ6997]旅行商问题二

[COJ6997]旅行商问题二

试题描述

Bob是一名旅行商,Bob同时也是一个哲学家,他深知到了一个地方就要掏出钱包把所有景点都玩到。一个城市有N个景点,其中N-1条无向道路链接成一个连通图。Bob出来带的经费是有限的,他希望从1号景点出发,把所有景点都走到(不必返回1点)。每个点不一定只走一次,但是要保证从一号点游览完所有景点的路程最小,他希望你告诉他这个路程。

输入

第一行:一个数N,表示有N个景点(包括1点)
下面N-1行:每行表示一条边,A,B,C表示A点到B点有一条长度为C的边。

输出

游览完所有点的最小路程。

输入示例

3
1 2 3
2 3 3

输出示例

6

数据规模及约定

N<=1000

题解

搞一个树形 dp,设 f(i) 表示对于子树 i,遍历一遍所有节点但不回到节点 i 的最短路长度;g(i) 表示遍历一遍子树 i 且回到节点 i 的最短长度。

那么显然

最后答案是 f(1)。

#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cmath>
#include <stack>
#include <vector>
#include <queue>
#include <cstring>
#include <string>
#include <map>
#include <set>
using namespace std;

int read() {
    int x = 0, f = 1; char c = getchar();
    while(!isdigit(c)){ if(c == '-') f = -1; c = getchar(); }
    while(isdigit(c)){ x = x * 10 + c - '0'; c = getchar(); }
    return x * f;
}

#define maxn 1010
#define maxm 2010
int n, m, head[maxn], next[maxm], to[maxm], dist[maxm];

void AddEdge(int a, int b, int c) {
	to[++m] = b; dist[m] = c; next[m] = head[a]; head[a] = m;
	swap(a, b);
	to[++m] = b; dist[m] = c; next[m] = head[a]; head[a] = m;
	return ;
}

int f[maxn], g[maxn];
void dp(int u, int fa) {
	g[u] = 0;
	int tmp = 0;
	for(int e = head[u]; e; e = next[e]) if(to[e] != fa) {
		dp(to[e], u);
		g[u] += g[to[e]] + 2 * dist[e];
		tmp = max(tmp, g[to[e]] - f[to[e]] + dist[e]);
	}
	f[u] = g[u] - tmp;
	return ;
}

int main() {
	n = read();
	for(int i = 1; i < n; i++) {
		 int a = read(), b = read(), c = read();
		 AddEdge(a, b, c);
	}
	
	dp(1, 0);
	
	printf("%d
", f[1]);
	
	return 0;
}

 并不知道数据范围为什么这么小

原文地址:https://www.cnblogs.com/xiao-ju-ruo-xjr/p/5865172.html