题目大意
给定一个
n
个点,
1≤n≤200,1≤m≤19900 ,边权 w≤105
题目分析
我们枚举边,计算点在每条边上时的最优答案。
令当前枚举的边是
(a,b)
,边长为
l
,我们设选取的点距离
可以发现我们能够计算出对于一个点, x 在什么范围的时候
x 能使两个元素取等号时答案最小,那么我们可以把这个
我们需要一个能够支持加入、删除查询最大值的数据结构,使用set即可。当然,由于这个过程是一个集合不断删数,一个集合不断加数,正反两次预处理即可得到最大值。
最短路使用
时间复杂度 O(nmlog2n+n3) 。
代码实现
#include <algorithm>
#include <iostream>
#include <climits>
#include <cstdio>
#include <cctype>
#include <set>
using namespace std;
typedef long double db;
inline int read()
{
int x=0,f=1;
char ch=getchar();
while (!isdigit(ch)) f=ch=='-'?-1:f,ch=getchar();
while (isdigit(ch)) x=x*10+ch-'0',ch=getchar();
return x*f;
}
db max(db x,db y){return x>y?x:y;}
db min(db x,db y){return x<y?x:y;}
const int INF=INT_MAX/2;
const int N=205;
const int M=19950;
const int E=M<<1;
struct edge
{
int x,y,l;
}e[M];
struct key
{
db x;
int id;
}pts[N];
bool operator<(key a,key b){return a.x<b.x;}
int dis[N][N];
int n,m,tot;
db ans;
void floyd()
{
for (int k=1;k<=n;k++)
for (int i=1;i<=n;i++)
if (i!=k)
for (int j=1;j<=n;j++)
if (i!=j&&j!=k)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
}
db mx[2][N];
db getans(int x,db l,db r,db w)
{
db a=mx[1][x],b=mx[0][x-1];
db ret=(b-a+w)/2.0;
if (l<=ret&&ret<=r) return a+ret;
return min(max(a+l,b+w-l),max(a+r,b+w-r));
}
void calc()
{
ans=INF;
for (int i=1,x,y,l,cur;i<=m;i++)
{
x=e[i].x,y=e[i].y,l=e[i].l,tot=0;
mx[0][0]=0.0,mx[1][tot+1]=0.0;
for (int j=1;j<=n;j++)
{
db tmp=(dis[y][j]-dis[x][j]+l)/2.0;
if (0<=tmp&&tmp<=l) pts[++tot].x=tmp,pts[tot].id=j;
else if (tmp<0) mx[1][tot+1]=max(mx[1][tot+1],dis[y][j]);
else mx[0][0]=min(mx[0][0],dis[x][j]);
}
if (!tot) continue;
sort(pts+1,pts+1+tot);
pts[0].x=0.0;
for (int j=1;j<=tot;j++) mx[0][j]=max(mx[0][j-1],dis[y][pts[j].id]);
for (int j=tot;j>=1;j--) mx[1][j]=max(mx[1][j+1],dis[x][pts[j].id]);
for (int j=1;j<=tot;j++) if (pts[j].x!=pts[j-1].x) ans=min(ans,getans(j,pts[j-1].x,pts[j].x,l));
ans=min(ans,getans(tot+1,pts[tot].x,l,l));
}
}
int main()
{
freopen("radius.in","r",stdin),freopen("radius.out","w",stdout);
n=read(),m=read();
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
dis[i][j]=INF;
for (int i=1,x,y,z;i<=m;i++)
{
x=read(),y=read(),z=read();
dis[x][y]=min(dis[x][y],z),dis[y][x]=min(dis[y][x],z);
e[i].x=x,e[i].y=y,e[i].l=z;
}
for (int i=1;i<=n;i++) dis[i][i]=0;
floyd(),calc();
printf("%.2lf\n",(double)ans);
fclose(stdin),fclose(stdout);
return 0;
}