题意:给定一个n个点m条边的加权有向图,求平均权值最小的回路。
分析:使用二分法求解。对于一个猜测值mid,只需要判断是否存在平均值小于mid的回路。如何判断呢?假设存在一个包含k条边的回路,回路上各条变的权值为w1,w2,....,wk,那么
平均值小于mid意味着w1+w2+....+wk《K*mid,即:
(w1-mid)+(w2-mid)+...+(wk-mid)<0
换句话说,只要把每条边(a,b)的全w(a,b)变成w(a,b)-mid,再判断新图中是否有负权回路即可。
// File Name: 11090.cpp // Author: zlbing // Created Time: 2013/2/14 21:32:55 #include<iostream> #include<string> #include<algorithm> #include<cstdlib> #include<cstdio> #include<set> #include<map> #include<vector> #include<cstring> #include<stack> #include<cmath> #include<queue> using namespace std; #define MAXN 100 const int INF=1e9; struct Edge{ int from,to; double dist; }; struct BellmanFord{ int n,m; vector<Edge>edges; vector<int>G[MAXN]; bool inq[MAXN]; double d[MAXN]; int p[MAXN]; int cnt[MAXN]; void init(int n) { this->n=n; for(int i=0;i<n;i++)G[i].clear(); edges.clear(); } void AddEdge(int from,int to,int dist) { edges.push_back((Edge){from,to,dist}); m=edges.size(); G[from].push_back(m-1); } bool negativeCycle() { queue<int>Q; memset(inq,0,sizeof(inq)); memset(cnt,0,sizeof(cnt)); for(int i=0;i<n;i++) { d[i]=0;inq[0]=true;Q.push(i); } while(!Q.empty()) { int u=Q.front();Q.pop(); inq[u]=false; for(int i=0;i<G[u].size();i++) { Edge& e=edges[G[u][i]]; if(d[e.to]>d[u]+e.dist) { d[e.to]=d[u]+e.dist; p[e.to]=G[u][i]; if(!inq[e.to]) { Q.push(e.to); inq[e.to]=true; if(++cnt[e.to]>n) return true; } } } } return false; } }; BellmanFord solver; bool test(double x) { for(int i=0;i<solver.m;i++) solver.edges[i].dist-=x; bool ret=solver.negativeCycle(); for(int i=0;i<solver.m;i++) solver.edges[i].dist+=x; return ret; } int main(){ int T; scanf("%d",&T); for(int cas=1;cas<=T;cas++) { int n,m; scanf("%d%d",&n,&m); solver.init(n); int a,b,c; int maxn=0; while(m--) { scanf("%d%d%d",&a,&b,&c); a--,b--; maxn=max(maxn,c); solver.AddEdge(a,b,c); } printf("Case #%d: ",cas); if(!test(maxn+1))printf("No cycle found.\n"); else{ double L=0,R=maxn; while(R-L>1e-3) { double M=L+(R-L)/2; if(test(M))R=M; else L=M; } printf("%.2lf\n",L); } } return 0; }