一、题目
二、解法
我们首先做 ,求出任意两点最短路,然后我们枚举一条边 ,其长度为 ,设终点在这条边上,对于任意一个点 ,它的贡献是 ,我们要求的就是对于每一个 所有贡献的最大值。
可以考虑把点划分成两个集合 ,最短路经过 的划定到 集合,经过 划定到 集合,我们可以算出每个点集合变动的位置,把他们排序,在一个区间内解方程算出最小值 ,判断这个 在不在区间内,否则暴力取端点更新。对于 集合只会删除, 集合只会加入,所以我们可以用 维护 , 集合乱搞一下就行了,时间复杂度 。
#include<cstdio>
#include<algorithm>
#define fo(i,a,b) for(i=a;i<=b;i++)
using namespace std;
typedef double db;
const int maxn=200+10,maxm=50000+10;
const db eps=0.001;
int dis[maxn][maxn],from[maxm],go[maxm],dist[maxm],id[maxn],wz[maxn];
bool bz[maxn];
struct dong{
db x;
int id;
} a[maxn],b[maxn];
int i,j,k,t,n,m,top,tot,u,v,c;
db ans,p,q,x,l,r,c1,c2;
bool cmp(dong a,dong b){
return a.x<b.x;
}
int main(){
freopen("center.in","r",stdin);freopen("center.out","w",stdout);
scanf("%d%d",&n,&m);
fo(i,1,n)
fo(j,1,n)
if (i!=j) dis[i][j]=1000000000;
fo(i,1,m){
scanf("%d%d%d",&from[i],&go[i],&dist[i]);
dis[from[i]][go[i]]=dist[i];
dis[go[i]][from[i]]=dist[i];
}
fo(k,1,n)
fo(i,1,n)
if (i!=k)
fo(j,1,n)
if (j!=k)
if (i!=j)
dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);
ans=1000000000;
fo(i,1,m){
q=0;
u=from[i];v=go[i];c=dist[i];
a[1].x=a[1].id=a[2].id=0;a[top=2].x=c;
tot=0;
fo(j,1,n){
if (dis[j][u]<dis[j][v]+c){
p=(db)(dis[j][v]+c-dis[j][u])/2;
if (0<p&&p<c){
a[++top].x=p;
a[top].id=j;
}
b[++tot].x=dis[j][u];
b[tot].id=j;
}
else if (q<dis[j][v]) q=dis[j][v];
}
sort(a+1,a+top+1,cmp);
sort(b+1,b+tot+1,cmp);
fo(j,1,tot) bz[wz[b[j].id]=j]=0;
fo(j,1,top-1){
if (a[j].id){
bz[wz[a[j].id]]=1;
if (q<dis[a[j].id][v]) q=dis[a[j].id][v];
}
while (tot&&bz[tot]) tot--;
c1=b[tot].x;
c2=q;
x=(c2+c-c1)/2;
if (a[j].x<=x&&x<=a[j+1].x) ans=min(ans,c1+x);
else ans=min(ans,min(max(c1,c2+c),max(c1+c,c2)));
}
}
printf("%.2lf\n",ans);
}
鸣谢代码来源:WerKeyTom_FTD巨佬
原题实在是找不到,所以也交不了。。。