bellman_ford寻找平均权值最小的回路
给定一个有向图,如果存在平均值最小的回路,输出平均值。
使用二分法求解,对于一个猜测值mid,判断是否存在平均值小于mid的回路
如果存在平均值小于mid的包含k条边的回路,那么有w1+w2+w3+...+wk < k * mid,即(w1-mid)+(w2-mid)+..(wk-mid)<0,
即判断是否存在负权回路即可。
1 #include <stdio.h> 2 #include <string.h> 3 const int N = 50+10; 4 const int INF = 1<<30; 5 struct Edge 6 { 7 int u,v; 8 double weight; 9 }g[4000000]; 10 double dist[N]; 11 void relax(int u, int v,double weight) 12 { 13 if(dist[v] > dist[u] + weight) 14 dist[v] = dist[u] + weight; 15 } 16 bool bellman_ford(int n, int m) 17 { 18 int i,j; 19 for(i=0; i<n-1; ++i)//n-1循环 20 for(j=0; j<m; ++j)//枚举所有的边去松弛最短路径 21 { 22 relax(g[j].u,g[j].v,g[j].weight); 23 } 24 bool flag = false; 25 for(i=0; i<m; ++i) 26 if(dist[g[i].v] > dist[g[i].u] + g[i].weight) 27 { 28 flag = true; 29 break; 30 } 31 return flag; 32 } 33 bool test(double x,int n, int m) 34 { 35 int i; 36 for(i=0; i<m; ++i) 37 g[i].weight -= x; 38 bool ret = bellman_ford(n,m); 39 for(i=0; i<m; ++i) 40 g[i].weight += x; 41 return ret; 42 } 43 int main() 44 { 45 int n,m,i,t,tCase=1; 46 double l,r; 47 scanf("%d",&t); 48 while(t--) 49 { 50 scanf("%d%d",&n,&m); 51 for(i=1; i<=n; ++i) 52 dist[i] = INF; 53 l = r = 0; 54 for(i=0; i<m; ++i) 55 { 56 scanf("%d%d%lf",&g[i].u,&g[i].v,&g[i].weight); 57 r = r > g[i].weight ? r : g[i].weight; 58 } 59 if(!test(r+1,n,m))printf("Case #%d: No cycle found.\n",tCase++); 60 else 61 { 62 double mid; 63 64 while(r-l>0.001)//因为题目要求保留2位小数,所以当r-l>0.001时,l就是答案。 65 { 66 double mid = (r + l ) / 2; 67 if(test(mid,n,m)) 68 r = mid; 69 else 70 l = mid; 71 } 72 printf("Case #%d: %.2lf\n",tCase++,l); 73 } 74 75 } 76 return 0; 77 }