题目:
http://acm.hdu.edu.cn/showproblem.php?pid=3721
题意:
n个点的有边权的树,移动一条边(即改变边的两个端点),使得树的直径最短。
思路:
移动的边在原树的直径上,移动后原树变成两棵子树,求出两棵子树的直径。
枚举子树直径上的点,决定移动边的两个端点,求出最小的距离。
AC.
#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <cmath>
using namespace std;
const int inf = 0x3f3f3f3f;
const int maxn = 2505;
int tot, head[maxn];
struct Edge{
int to, w, next;
}edge[maxn*2];
void init()
{
tot = 0;
memset(head, -1, sizeof(head));
}
void addedge(int u, int v, int w)
{
edge[tot].to = v;
edge[tot].w = w;
edge[tot].next = head[u];
head[u] = tot++;
}
int num[maxn];
int res, point;
void dfs(int u, int fa)
{
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(v == fa) continue;
num[v] = num[u] + w;
if(res < num[v]) {
res = num[v];
point = v;
}
dfs(v, u);
}
}
struct Path{
int to, id;
}path[maxn];
void dfs1(int u, int fa)
{
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(v == fa) continue;
num[v] = num[u] + w;
path[v].to = u; path[v].id = i;
if(res < num[v]) {
res = num[v];
point = v;
}
dfs1(v, u);
}
}
int now;
int smpath[maxn];
int nog1, nog2;
void dfsmall(int u, int fa)
{
if(u == now) return;
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(nog1 == i || nog2 == i) continue;
if(v == fa) continue;
num[v] = num[u] + w;
if(res < num[v]) {
res = num[v];
point = v;
}
dfsmall(v, u);
}
}
void dfsmall2(int u, int fa)
{
for(int i = head[u]; ~i; i = edge[i].next) {
int v = edge[i].to, w = edge[i].w;
if(nog1 == i || nog2 == i) continue;
if(v == fa) continue;
num[v] = num[u] + w;
smpath[v] = u;
if(res < num[v]) {
res = num[v];
point = v;
}
dfsmall2(v, u);
}
}
void initdfs()
{
res = 0;
memset(num, 0, sizeof(num));
}
int main()
{
// freopen("in", "r", stdin);
int TT, ca = 1;
scanf("%d", &TT);
while(TT--) {
int n;
scanf("%d", &n);
init();
int u, v, w;
for(int i = 1; i < n; ++i) {
scanf("%d%d%d", &u, &v, &w);
addedge(u, v, w);
addedge(v, u, w);
}
memset(path, -1, sizeof(path));
int S, T;
initdfs(); dfs(1, 1);
S = point;
initdfs(); dfs1(S, S);
T = point;
//printf("%d, %d\n", S, T);
int ans = inf, r;
int s1, t1, s2, t2, p1, p2;
for(int i = T; ~i; i = path[i].to) {
int id = path[i].id;
if(id == -1) break;
int u = edge[id].to, v = edge[id^1].to;
nog1 = id; nog2 = id^1;
r = edge[id].w;
memset(smpath, -1, sizeof(smpath));
initdfs(); dfsmall(u, u);
s1 = point;
initdfs(); dfsmall2(s1, s1);
t1 = point;
int r1 = num[t1];
// printf("****(%d, %d) = %d\n", s1, t1, num[t1]);
int tmp = inf;
for(int j = t1; ~j; j = smpath[j]) {
int cnt = max(num[t1]-num[j], num[j]);
tmp = min(tmp, cnt);
}
// printf("half path = %d\n", tmp);
r += tmp;
memset(smpath, -1, sizeof(smpath));
initdfs(); dfsmall(v, v);
s2 = point;
initdfs(); dfsmall2(s2, s2);
t2 = point;
int r2 = num[t2];
// printf("****(%d, %d) = %d\n", s2, t2, num[t2]);
tmp = inf;
for(int j = t2; ~j; j = smpath[j]) {
int cnt = max(num[t2]-num[j], num[j]);
tmp = min(tmp, cnt);
}
// printf("half path = %d\n", tmp);
r += tmp;
//printf("(%d, %d) = %d\n\n", u, v, r);
r = max(r, max(r1, r2));
ans = min(ans, r);
}
printf("Case %d: %d\n", ca++, ans);
}
return 0;
}