P3199 [HNOI2009]最小圈(二分答案+spfa判斷負環)
阿新 • • 發佈:2022-04-01
題意
在圖中找一個環,使得環上邊權之和除以節點個數最小,求這個最小平均值
輸入格式
第一行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; }