【jzoj4884】【图的半径】

来源:互联网 发布:吉他伴奏软件 编辑:程序博客网 时间:2024/04/28 09:50

题目大意

给出一副带权无向图,求图的半径,中点可以在边上。

解题思路

先求出两两最短路,枚举一条边,考虑最短路从哪一端走的临界点,把所有边的临界点排序,发现走左端的点逐渐减少,右端的点逐渐增多,可以排序后o(n)维护左端最大和右端最大,从而算出经过当前边的直径,取最大值即答案。

code

#include<set>#include<cmath>#include<cstdio>#include<cstring>#include<iostream>#include<algorithm>#define LL long long#define LD double#define max(a,b) ((a>b)?a:b)#define min(a,b) ((a>b)?b:a)#define fo(i,j,k) for(int i=j;i<=k;i++)#define fd(i,j,k) for(int i=j;i>=k;i--)using namespace std;int const inf=1e9,maxn=200,maxm=2*1e4,mod1=1e9+7,mod2=998244353,size=29989;int n,m,u[maxm+10],v[maxm+10],w[maxm+10],mxx[maxn+10];LD dis[maxn+10][maxn+10];struct rec{    int a,b;};rec a[maxn+10];bool cmp(rec x,rec y){    return x.a<y.a;}multiset<int>s;int main(){    //freopen("radius.in","r",stdin);    //freopen("radius.out","w",stdout);    freopen("d.in","r",stdin);    freopen("d.out","w",stdout);    scanf("%d%d",&n,&m);    fo(i,1,n+1)fo(j,1,n+1)dis[i][j]=inf;    fo(i,1,m){        scanf("%d%d%d",&u[i],&v[i],&w[i]);        dis[u[i]][v[i]]=dis[v[i]][u[i]]=min(dis[u[i]][v[i]],w[i]);    }    fo(i,1,n+1)dis[i][i]=0;    fo(k,1,n)        fo(i,1,n)            fo(j,1,n)                dis[i][j]=min(dis[i][j],dis[i][k]+dis[k][j]);    LD ans=inf;    fo(i,1,m){        int cnt=0;        fo(j,1,n){            a[++cnt].a=(dis[j][v[i]]-dis[j][u[i]]+w[i])/2.0;            a[cnt].b=j;        }        sort(a+1,a+cnt+1,cmp);a[cnt+1].a=w[i];int mx=0;mxx[cnt+1]=0;        fd(j,cnt,1){            mxx[j]=max(mxx[j+1],dis[a[j].b][u[i]]);        }        fo(j,1,cnt+1){            LD tmp;            if(j!=cnt+1)tmp=(mx-mxx[j]+w[i])/2.0;            else tmp=0;            if((a[j-1].a<=tmp)&&(tmp<=a[j].a))ans=min(ans,mx+w[i]-tmp);            if(j!=cnt+1)mx=max(mx,dis[a[j].b][v[i]]);        }    }    printf("%.2lf",ans);    return 0;}
0 0
原创粉丝点击