Center

一、题目

在这里插入图片描述

二、解法

我们首先做 f l o y d floyd ,求出任意两点最短路,然后我们枚举一条边 ( u , v ) (u,v) ,其长度为 c c ,设终点在这条边上,对于任意一个点 i i ,它的贡献是 min ( d i s [ i ] [ u ] + x , d i s [ i ] [ v ] + c x ) \min(dis[i][u]+x,dis[i][v]+c-x) ,我们要求的就是对于每一个 x x 所有贡献的最大值。

可以考虑把点划分成两个集合 A , B A,B ,最短路经过 u u 的划定到 A A 集合,经过 v v 划定到 B B 集合,我们可以算出每个点集合变动的位置,把他们排序,在一个区间内解方程算出最小值 x x ,判断这个 x x 在不在区间内,否则暴力取端点更新。对于 A A 集合只会删除, B B 集合只会加入,所以我们可以用 s e t set 维护 A A B B 集合乱搞一下就行了,时间复杂度 O ( n 3 log n ) O(n^3\log n)

#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巨佬

原题实在是找不到,所以也交不了。。。

发布了217 篇原创文章 · 获赞 12 · 访问量 5150

猜你喜欢

转载自blog.csdn.net/C202044zxy/article/details/104064857