[bzoj1486]最小圈
分数规划。
用dfs判断一下是否有负圈。
然后二分。
其实这道题在lrj的白书上面有,“再谈BF算法”中讲过将求图上环平均值转换到二分的方法。

1 #include <iostream> 2 #include <algorithm> 3 #include <cstdio> 4 #include <cstring> 5 #include <cstdlib> 6 #include <queue> 7 #include <string> 8 #include <vector> 9 #include <cmath> 10 using namespace std; 11 12 const int N=20000; 13 int h[N],r[N],to[N],tot,n,m; 14 double w[N],ans; 15 void add(int u,int v,double c){ 16 to[tot]=v; 17 r[tot]=h[u]; 18 w[tot]=c; 19 h[u]=tot++; 20 } 21 22 bool v[N],tmp;double d[N]; 23 void dfs(int x,double mid){ 24 v[x]=1; 25 for(int i=h[x];i!=-1;i=r[i]){ 26 if(d[to[i]]>d[x]+w[i]-mid){ 27 if(v[to[i]])return tmp=1,void(); 28 d[to[i]]=d[x]+w[i]-mid; 29 dfs(to[i],mid); 30 if(tmp)return; 31 } 32 } 33 v[x]=0; 34 } 35 bool check(double mid){ 36 memset(v,0,sizeof(v)); 37 memset(d,0,sizeof(d)); 38 tmp=0; 39 for(int i=1;i<=n;i++){dfs(i,mid);if(tmp)return 1;} 40 return 0; 41 } 42 43 int main(){ 44 memset(h,-1,sizeof(h)); 45 scanf("%d%d",&n,&m); 46 for(int i=1;i<=m;i++){ 47 int u,v; 48 double c; 49 scanf("%d%d%lf",&u,&v,&c); 50 add(u,v,c); 51 } 52 double l=-10000000,r=10000000; 53 while(r-l>0.0000000001){ 54 double mid=(l+r)/2; 55 if(check(mid))ans=r=mid; 56 else l=mid; 57 } 58 printf("%.8lf\n",ans); 59 }