图的绝对中心的定义是图上一个点(可以在结点上也可以在边上)到图上所有点的距离最大值最小。
我们可以得到,到图绝对中心距离相等的点有两个。
我们用
d
(
i
,
j
)
d(i,j)
d(i,j)表示结点
i
i
i到
j
j
j的最短距离,
r
k
(
i
,
j
)
rk(i,j)
rk(i,j)表示第
i
i
i个结点到其他结点距离中第
j
j
j小的那个。
设边
e
=
(
u
,
v
,
w
)
e=(u,v,w)
e=(u,v,w)的一点
c
c
c距离
u
u
u的距离为
x
x
x,到结点
i
i
i的距离为
f
(
c
,
i
)
=
min
(
d
(
u
,
i
)
+
x
,
d
(
v
,
i
)
+
w
−
x
)
f(c,i)=\min(d(u,i)+x,d(v,i)+w-x)
f(c,i)=min(d(u,i)+x,d(v,i)+w−x)。
f
(
c
,
i
)
f(c,i)
f(c,i)的函数图像是一个折线。
max
i
=
1
n
f
(
c
,
i
)
\max\limits_{i=1}^{n}f(c,i)
i=1maxnf(c,i)的最小值就是图中心的候选点之一。
设
a
n
s
ans
ans为直径长度。
1、绝对中心在结点上,就是某一结点到最远点的距离。
2、绝对中心在边上,就是函数图像的转折点上。此时距离
u
u
u的相邻两个端点
i
1
,
i
2
i_1,i_2
i1,i2满足
d
(
u
,
i
1
)
<
d
(
u
,
i
2
)
,
d
(
v
,
i
1
)
>
d
(
v
,
i
2
)
d(u,i_1)<d(u,i_2),d(v,i_1)>d(v,i_2)
d(u,i1)<d(u,i2),d(v,i1)>d(v,i2)。迭代计算即可。
int d[N][N],rk[N][N],val[N],n,m,ans=inf;
int u[N*N],v[N*N],w[N*N];
void floyd()
{
int i,j,k;
for(k=1;k<=n;k++)
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
d[i][j]=min(d[i][k]+d[k][j],d[i][j]);
}
int cmp(int x,int y)
{
return val[x]<val[y];
}
void core()
{
int i,j,k;
floyd();
for(i=1;i<=n;i++)
{
for(j=1;j<=n;j++)
{
rk[i][j]=j;
val[j]=d[i][j];
}
sort(rk[i]+1,rk[i]+n+1,cmp);
}
//图中心在结点上
for(i=1;i<=n;i++)
ans=min(ans,d[i][rk[i][n]]*2);
//图中心在边上
for(i=1;i<=m;i++)
{
for(k=n,j=n-1;j>=1;j--)
{
if(d[v[i]][rk[u[i]][j]]>d[v[i]][rk[u[i]][k]])
{
ans=min(ans,d[u[i]][rk[u[i]][j]]+d[v[i]][rk[u[i]][k]]+w[i]);
k=j;
}
}
}
}
int main()
{
int i,j;
scanf("%d%d",&n,&m);
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
d[i][j]=(i==j?0:inf);
for(i=1;i<=m;i++)
{
scanf("%d%d%d",&u[i],&v[i],&w[i]);
d[u[i]][v[i]]=min(d[u[i]][v[i]],w[i]);
d[v[i]][u[i]]=min(d[v[i]][u[i]],w[i]);
}
core();
printf("%.9lf\n",ans*1.0/2);
return 0;
}