【jzoj4884】【图的半径】

题目大意

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

解题思路

先求出两两最短路,枚举一条边,考虑最短路从哪一端走的临界点,把所有边的临界点排序,发现走左端的点逐渐减少,右端的点逐渐增多,可以排序后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
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值