您的位置:首页 > 其它

【BZOJ】2237: [NCPC2009]Flight Planning

2015-11-22 13:42 337 查看

题意

\(n(1 \le n \le 2500)\)个点的树,求删掉一条边再加上一条边使得还是一棵树,且任意两点最大距离最小。

分析

考虑枚举删掉每一条边,我们只需要考虑如何加边容易求得新树的最大距离。

当然是直径的一半咯。

题解

枚举每一条边,然后求两个连通块的直径,然后最大距离\(=max(len1, len2, (len1+1)/2+(len2+1)/2+1)\)

#include <bits/stdc++.h>
using namespace std;
const int N=2505;
struct E {
int next, to;
}e[N<<1];
int ihead
, d
, cnt, clr, n;
void add(int x, int y) {
e[++cnt]=(E){ihead[x], y}; ihead[x]=cnt;
e[++cnt]=(E){ihead[y], x}; ihead[y]=cnt;
}
void dfs(int x, int f) {
for(int i=ihead[x]; i; i=e[i].next) {
int y=e[i].to;
if(y==f || i==clr || i==clr-1) {
continue;
}
d[y]=d[x]+1;
dfs(y, x);
}
}
int getlen(int x) {
memset(d, 0, sizeof(int)*(n+1));
dfs(x, 0);
for(int i=1; i<=n; ++i) {
if(d[i]>d[x]) {
x=i;
}
}
memset(d, 0, sizeof(int)*(n+1));
dfs(x, 0);
for(int i=1; i<=n; ++i) {
if(d[i]>d[x]) {
x=i;
}
}
return d[x];
}
int x
, y
;
int main() {
scanf("%d", &n);
for(int i=1; i<n; ++i) {
scanf("%d%d", &x[i], &y[i]);
add(x[i], y[i]);
}
int ans=n;
for(int i=1; i<n; ++i) {
clr=i*2;
int len1=getlen(x[i]), len2=getlen(y[i]), a=(len1+1)/2, c=(len2+1)/2;
ans=min(ans, max(a+c+1, max(len1, len2)));
}
printf("%d\n", ans);
return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: