1. 程式人生 > 其它 >P3199 [HNOI2009]最小圈(二分答案+spfa判斷負環)

P3199 [HNOI2009]最小圈(二分答案+spfa判斷負環)

題目傳送門

題意

在圖中找一個環,使得環上邊權之和除以節點個數最小,求這個最小平均值

輸入格式

第一行2個正整數,分別為\(n\)\(m\),並用一個空格隔開,只用\(n=|V|\),\(m=|E|\)分別表示圖中有\(n\)個點\(m\)條邊。 接下來\(m\)行,每行3個數\(i\),\(j\),\(w_{i,j}\),表示有一條邊\((i,j)\)且該邊的權值為\(w_{i,j}\).輸入資料保證圖G=(V,E)連通,存在圈且有一個點能到達其他所有點。

輸出格式

求出\(G\)中所有環\(c\)的平均值的最小值

資料範圍

\(n≤3000\),\(m≤10000\),\(|w_{i,j}|\leq10^7\)

樣例

input

4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3

output

3.66666667

思路

二分一個mid,然後我們把每條邊得邊權看作\((e[i].val-mid)\),然後在圖上判負環,若有負環則\(R=mid\),否則\(L=mid\),直到達到精度要求

code

#include <bits/stdc++.h>
using  namespace  std;

typedef long long ll;
typedef unsigned long long ull;
//#pragma GCC optimize(3)
#define pb push_back
#define is insert
#define PII pair<int,int>
#define PLL pair<ll,ll>
#define show(x) cerr<<#x<<" : "<<x<<endl;
//mt19937 mt19937random(std::chrono::system_clock::now().time_since_epoch().count());
//ll getRandom(ll l,ll r){return uniform_int_distribution<ll>(l,r)(mt19937random);}

const int INF=0x3f3f3f3f;//2147483647;
const int N=3050,M=1e4+50;
const ll mod=998244353;

int head[N];
int tot=0;
struct node {
    int to,nxt;
    long double dis;
}e[M],tmp[M];
void add_edge(int u,int v,long double d){
    tmp[++tot].to=v;
    tmp[tot].dis=d;
    tmp[tot].nxt=head[u];
    head[u]=tot;
}
long double d[N];
int n,m;
bool vis[N];
bool spfa(long double mid){
    memset(vis,0,sizeof(vis));
    queue<int>q;
    for(int i=0;i<n;i++){
        q.push(i);
        vis[i]=1;
    }
    for(int i=1;i<=tot;i++){
        e[i]=tmp[i];
        e[i].dis-=mid;
    }
    vector<int> pre(n, -1);
    int idx = 0;
    auto detectCycle = [&]() {
        vector<int> vec;
        vector<bool> inStack(n, false);
        vector<bool> vis(n, false);
        for (int i = 0; i < n; i++) {
            if (!vis[i]) {
                for (int j = i; j != -1; j = pre[j]) {
                    if (!vis[j]) {
                        vis[j] = true;
                        vec.push_back(j);
                        inStack[j] = true;
                    } else {
                        if (inStack[j]) return true;
                        break;
                    }
                }
                for (int j : vec) inStack[j] = false;
                vec.clear();
            }
        }
        return false;
    };
    while(!q.empty()){
        int u=q.front();q.pop();vis[u]=0;
        for(int i=head[u];i;i=e[i].nxt){
            int v=e[i].to;
            if(d[v]>d[u]+e[i].dis){
                d[v]=d[u]+e[i].dis;
                pre[v]=u;
                if(++idx==n){
                    idx=0;
                    if(detectCycle())return true;
                }
                if(!vis[v]){
                    q.push(v);
                    vis[v]=1;
                }
            }
        }
    }
    if(detectCycle())return true;
    return false;
}
void solve() {
    cin>>n>>m;
    for(int i=1;i<=m;i++){
        int u,v;long double val;
        cin>>u>>v>>val;
        add_edge(u-1,v-1,val);
    }
    long double delta=1e-10;
    long double l=-10000005.0,r=10000005.0;
    while(fabs(l-r)>=delta){
        long double mid=(l+r)/2.0;
        if(spfa(mid)){
            r=mid;
        }
        else {
            l=mid;
        }
    }
    cout<<fixed<<setprecision(8)<<l;
}

signed main(){
    ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
    //freopen("C:\\Users\\ILLUME\\Downloads\\P3199_4.in","r",stdin);
    int __=1;//cin>>__;
    while(__--){
        solve();
    }
    return 0;
}