最小圈

 

试题描述

考虑带权的有向图 G=(V,E) 以及 w:E→R,每条边 e=(i,j)(i≠j,i∈V,j∈V)的权值定义为 w(i,j),令 n=∣V∣。c=(c1,c2,⋯,ck)(ci∈V)是 G 中的一个圈当且仅当 (ci,ci+1)(1≤i<k)都在 E 中,这时称 k 为圈 c 的长度。同时令 c(k+1)=c,并定义圈 c=(c1,c2,⋯,ck)的平均值为:

即 c 上所有边的权值的平均值。
令 μ∗(c)=min{μ(c)}为 G 中所有圈 c 的平均值的最小值。现在的目标是:在给定了一个图 G=(V,E)以及 w:E→R之后,请求出 G 中所有圈 c 的平均值的最小值 μ∗(c)=min{μ(c)}。
输入
第一行包含两个正整数 n 和 m,并用一个空格隔开,其中 n=∣V∣,m=∣E∣,分别表示图中有 n 个顶点和 m 条边;
接下来 m 行,每行包含用空格隔开的三个数 i,j,w(i,j),表示有一条边 (i,j)且该边的权值为w(i,j)。
输入数据保证图 G=(V,E)连通,存在圈且有一个点能到达其他所有点。
输出
仅包含一个实数 μ∗=min{μ(c)},要求输出到小数点后 8 位。
输入示例
样例输入
1 4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
样例输入 2
2 2
1 2 -2.9
2 1 -3.1
输出示例
样例输出 1
3.66666667
样例输出 2
-3.00000000
其他说明
数据范围与提示
对于 20% 的数据,1≤n≤100,1≤m≤1000;
对于 40%的数据,1≤n≤1000,1≤m≤5000;
对于 100% 的数据,1≤n≤3000,1≤m≤10^4,∣wi,j∣≤10^7。
输入保证 1≤i,j≤n。

 第一眼是和WordStrings一个尿性,然而就是一样的

二分答案加上SPFA

就很奈斯,然而调的时候把二分写错了,被人打了好久QAQ

下面给出代码:

#include<iostream>
#include<algorithm>
#include<cstdio>
#include<cstdlib>
#include<cstring>
#include<string>
#include<cmath>
#include<queue>
using namespace std;
inline int rd(){
    int x=0,f=1;
    char ch=getchar();
    for(;!isdigit(ch);ch=getchar()) if(ch=='-') f=-1;
    for(;isdigit(ch);ch=getchar()) x=x*10+ch-'0';
    return x*f;
}
void write(int x){
    if(x<0) putchar('-'),x=-x;
    if(x>9) write(x/10);
    putchar(x%10+'0');
    return ;
}
int n,m;
int head[1000006],to[1000006],nxt[1000006];
double c[1000006],v[1000006];
int total=0;
void add(int x,int y,double z){
    total++;
    to[total]=y;
    v[total]=z;
    nxt[total]=head[x];
    head[x]=total;
    return ;
}
int book[1000006];
double dis[1000006];
bool spfa_find_circle(int x,double h){//SPFA判环 
    book[x]=1;
    for(int e=head[x];e;e=nxt[e]){
        if(dis[to[e]]>dis[x]+v[e]-h){//如果更优,就判断是否为环 
            if(book[to[e]]) return true;
            else{
                dis[to[e]]=dis[x]+v[e]-h;//更新 
                if(spfa_find_circle(to[e],h)) return true;
            }
        }
    }
    book[x]=0;
    return false;
}
bool check(double x){
    for(int i=1;i<=n;i++) dis[i]=book[i]=0;
    bool f=0;
    for(int i=1;i<=n;i++){//枚举起点 
        if(spfa_find_circle(i,x)){
            f=1;
            break;
        }
    }
    return f;
}
int main()
{
    n=rd();
    m=rd();
    double minn=999999999,maxn=-999999999;
    for(int i=1;i<=m;i++){
        int x,y;
        double z;
        x=rd();
        y=rd();
        scanf("%lf",&z);
        add(x,y,z);//选出最大和最小值,开始的时候取得太大了,然后爆了,因为平均数肯定在最大和最小值之间 
        minn=min(minn,z);
        maxn=max(maxn,z);
    }
    double l=minn,r=maxn;
    while(r-l>1e-9){
        double mid=(r+l)/2.0;//写成了(r-l)/2.0 QAQ 
        if(check(mid)) r=mid;
        else l=mid;
    }
    printf("%.8lf",r);
    return 0;
}

 

posted @ 2018-09-10 18:37  Bruce--Wang  阅读(162)  评论(0编辑  收藏  举报