题意:给出n个点m条边的加权有向图,求平均值最小的回路
自己想的是用DFS找环(真是too young),在比较找到各个环的平均权值,可是代码实现不了,觉得又不太对
后来看书= =好巧妙的办法, 使用二分法求解,首先记录下来这m条边的最大权值ub
然后可以猜测一个mid,只需要判断是否存在平均值小于mid的回路 假设存在一个包含k条边的回路,回路上各条边的权值分别为w1,w,2,w3,----,wk
那么
w1+w2+w3+----+wk<k*mid
又因为联想到Bellman_Ford可以解决负环,把上式转化一下
(w1-mid)+(w2-mid)+(w3-mid)+----(wk-mid)<0
这样先将每条边w(a,b)转化成为w(a,b)-mid,再判断“新”的图中是否存在负环
自己看的时候有两个不明白的,就是最开始判断的时候为什么要用ub+1,
是因为ub+1是最差的答案了,它能够尽可能的使得每条边负得最多,如果在这种情况下都找不到负环,那么一定不存在负环
然后就是如果在ub+1的条件下能够找到负环,那么就二分查找一步步找出平均值最小的环,直到到达循环退出的精度
代码学习的标程= =
1 #include<iostream> 2 #include<cstdio> 3 #include<cstring> 4 #include <cmath> 5 #include<stack> 6 #include<vector> 7 #include<map> 8 #include<set> 9 #include<queue> 10 #include<algorithm> 11 #define mod=1e9+7; 12 using namespace std; 13 14 typedef long long LL; 15 const int INF = 0x7fffffff; 16 const int maxn=10005; 17 18 struct Edge{ 19 int from,to; 20 double dist; 21 }; 22 23 struct BellmanFord{ 24 int n,m; 25 vector<Edge> edges; 26 vector<int> G[maxn]; 27 bool inq[maxn]; 28 double d[maxn]; 29 int p[maxn]; 30 int cnt[maxn]; 31 32 void init(int n){ 33 this->n=n; 34 for(int i=0;i<n;i++) G[i].clear(); 35 edges.clear(); 36 } 37 38 void AddEdges(int from,int to,double dist){ 39 edges.push_back((Edge){from,to,dist}); 40 m=edges.size(); 41 G[from].push_back(m-1); 42 } 43 44 bool negativeCycle(){ 45 queue<int> Q; 46 memset(inq,0,sizeof(inq)); 47 memset(cnt,0,sizeof(cnt)); 48 for(int i=0;i<n;i++) {d[i]=0;inq[0]=true;Q.push(i);} 49 50 while(!Q.empty()){ 51 int u=Q.front();Q.pop(); 52 inq[u]=false; 53 for(int i=0;i<G[u].size();i++){ 54 Edge& e=edges[G[u][i]]; 55 if(d[e.to]>d[u]+e.dist){ 56 d[e.to]=d[u]+e.dist; 57 p[e.to]=G[u][i]; 58 if(!inq[e.to]){ 59 Q.push(e.to); 60 inq[e.to]=true; 61 if(++cnt[e.to]>n) 62 return true; 63 } 64 } 65 } 66 } 67 return false; 68 } 69 }; 70 71 BellmanFord solver; 72 73 bool test(double x){ 74 for(int i=0;i<solver.m;i++) 75 solver.edges[i].dist-=x; 76 77 bool ret=solver.negativeCycle(); 78 for(int i=0;i<solver.m;i++) 79 solver.edges[i].dist+=x; 80 return ret; 81 } 82 83 int main(){ 84 int T; 85 scanf("%d",&T); 86 for(int kase=1;kase<=T;kase++){ 87 int n,m; 88 scanf("%d %d",&n,&m); 89 solver.init(n); 90 int ub=0; 91 while(m--){ 92 int u,v,w; 93 scanf("%d %d %d",&u,&v,&w);u--;v--;ub=max(ub,w); 94 solver.AddEdges(u,v,w); 95 } 96 printf("Case #%d: ",kase); 97 if(!test(ub+1)) printf("No cycle found.\n"); 98 else{ 99 double L=0,R=ub; 100 while(R-L>1e-3){ 101 double M=L+(R-L)/2; 102 if(test(M)) R=M;else L=M; 103 } 104 printf("%.2lf\n",L); 105 } 106 } 107 return 0; 108 }