1. 程式人生 > >BZOJ1486&&洛谷 P3199 [HNOI2009]最小圈

BZOJ1486&&洛谷 P3199 [HNOI2009]最小圈

01分數規劃->二分+dfs判負環

思路

考慮在平均值最小的環上的每條邊都減去平均值之後,環的總權值是0,而平均值大於這個環的平均值的環每條邊減去最小環的平均值總權值會大於零,反過來,小環減去大環的平均值會出現負權環,所以二分的判斷條件就有了,二分一個最小平均值,若圖中存在一個負環,那麼就存在更小的平均值

吐槽

我把有向圖建成了無向圖,一直跑不過樣例QWQ

程式碼

//By AcerMo
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
#define d double using namespace std; const int M=20500; const double eps=1e-9; int n,m; double dis[M],w[M]; int to[M],nxt[M],head[M],cnt,vis[M]; inline void read(int &x) { x=0;char ch=getchar(); while (!isdigit(ch)) ch=getchar(); while (isdigit(ch)) x=x*10+ch-'0',ch=getchar(); return ; } inline void
add(int x,int y,d z) { to[++cnt]=y;w[cnt]=z;nxt[cnt]=head[x];head[x]=cnt; return ; } inline bool dfs(int x,d l) { vis[x]=1; for (int i=head[x];i;i=nxt[i]) if (dis[to[i]]>dis[x]+w[i]-l) { if (vis[to[i]]) return 1; dis[to[i]]=dis[x]+w[i]-l; if (dfs(to[i],l)) return 1; } vis[x]=0; return
0; } signed main() { read(n);read(m); int x,y;d z; for (int i=1;i<=m;i++) read(x),read(y),cin>>z,add(x,y,z); double l=-1e8,r=1e8; while (r-l>eps) { double mid=(l+r)/2.0;int fl=0; fill(vis,vis+n+1,0); fill(dis,dis+n+1,0);; for (int i=1;i<=n&&!fl;i++) if (dfs(i,mid)) fl=1; if (fl) r=mid; else l=mid; } printf("%.8lf",l); return 0; }