链接
https://codeforces.com/problemset/problem/1092/E
题解
花了一晚上写这道题(时间都用来调试
p
y
py
py代码了)
对每个连通分量找到一个点,使得这个点到其它点的距离的最大值最小,由于
n
≤
1000
n\leq1000
n≤1000可以直接暴力
O
(
n
2
)
O(n^2)
O(n2)
对于第
i
i
i个连通分量,记这个点为
c
e
n
t
e
r
i
center_i
centeri,这个最小的最大距离为
d
i
d_i
di(也就等于直径的一半)
然后找到最大的那个
d
i
d_i
di对应的
i
i
i,把其余的
c
e
n
t
e
r
j
center_j
centerj都直接连到
c
e
n
t
e
r
i
center_i
centeri上
为啥这样就最优?
记原来最远的两个点的距离为
D
D
D
当
D
D
D为偶数时:
那么最大的
d
i
d_i
di等于
D
2
D\over 2
2D,如果第二小的
d
i
d_i
di小于
D
2
D\over 2
2D,那么我构造出的树的直径是
D
D
D,是最优解
如果第二小的
d
i
d_i
di也等于
D
2
D\over2
2D,第三小的
d
i
d_i
di小于
D
2
\frac{D}{2}
2D,我构造出的树直径是
D
+
1
D+1
D+1
现在看一下有没有可能存在直径为
D
D
D的答案呢?
假设这条直径的两个端点为
u
,
v
u,v
u,v,假设那棵
d
i
d_i
di也等于
D
2
\frac{D}{2}
2D的树上离根节点距离最远的点是
t
t
t,那么不管怎么连,
u
u
u肯定最后和
t
t
t是连通的,显然想要构造尽量小的直径,我肯定直接把
u
u
u所在的
c
o
m
p
o
n
e
n
t
component
component上的某个点直接用一条边连接到
t
t
t所在的
c
o
m
p
o
n
e
n
t
component
component而不是经过多次中转which will lead to bigger answer.那么如果我在
u
u
u所在的
c
o
n
p
o
m
e
n
t
conpoment
conpoment上的点不是距离它恰好
D
2
\frac{D}{2}
2D的点,肯定答案会更劣,
t
t
t所在的分量中的点的选择可以用类似的方法证明,而从一个连通分量到另一个连通分量至少要经过
1
1
1的距离,所以答案不会小于
D
+
1
D+1
D+1
如果有三个及以上分量的
d
i
d_i
di都等于
D
2
\frac{D}{2}
2D,那么答案是
D
+
2
D+2
D+2
因为有一个分量通过走两条边到达了另一个分量,而因为这是树这样的情况是无法避免的
当
D
D
D为奇数时
证明是类似的
温馨提示
p
t
y
h
o
n
ptyhon
ptyhon代码调试了一晚上
期间还学会了怎么
t
r
y
,
c
a
t
c
h
try,catch
try,catch
最后发现
p
y
t
h
o
n
python
python的递归层数的最大值默认是
1000
1000
1000,而这道题恰好有
1000
1000
1000个点
所以就用了这个东西
sys.setrecursionlimit(n)
其中
n
n
n表示你要把递归层数的上限设为多少
代码
import sys
sys.setrecursionlimit(1100)
def dfs1(u,pre): #find the components
vis[u] = True
now.append(u)
for v in to[u]:
if v!=pre:dfs1(v,u)
def dfs2(u,pre): #calulate the distance
mxdist[u]=dist[u]
for v in to[u]:
if v!=pre:
dist[v] = dist[u]+1
dfs2(v,u)
mxdist[u]=max(mxdist[u],mxdist[v])
try:
lab = 1
n, m = [int(x) for x in input().split()]
to = [[] for i in range(n+10)]
dist = [0 for i in range(n+10)]
mxdist = [0 for i in range(n+10)]
lab = 2
for i in range(m):
u,v = [int(x) for x in input().split()]
to[u].append(v)
to[v].append(u)
com=[]
vis=[False for i in range(n+10)]
for i in range(1,n+1):
if vis[i]==False:
now=[]
dfs1(i,0)
com.append(now)
lab = 3
ct = []
mx = 0
for lis in com:
tmp = []
d = 0
for root in lis:
for u in lis:dist[u]=mxdist[u]=0
dfs2(root,0)
tmp.append((mxdist[root],root))
d = max( d, sum( sorted([ mxdist[u] for u in to[root] ])[-2:] ) )
#print(*[mxdist[u] for u in lis])
mx = max(mx,d)
#print('d =',d)
for x in tmp:
if x[0]==(d+1)//2:
center = [x[1] for x in tmp if x[0]==(d+1)//2][0]
ct.append( ((d+1)//2,center) )
#print(*ct)
lab = 4
ct.sort(reverse=True)
ans = []
for i in range(1,len(ct)):
mx = max(mx,ct[i][0]+1+ct[0][0])
if i>1:mx = max(mx,ct[i][0]+2+ct[1][0])
ans.append((ct[i][1],ct[0][1]))
print(mx)
for p in ans:
print(*p)
except Exception as e:
print('error after lable',lab,', type =',e)