UVa 11090 Going in Cycle!!【Bellman_Ford】

题意:给出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 }

时间: 2024-08-28 10:02:09

UVa 11090 Going in Cycle!!【Bellman_Ford】的相关文章

UVA 11090 - Going in Cycle!!(Bellman-Ford)

UVA 11090 - Going in Cycle!! 题目链接 题意:给定一个有向图,球平均权值最小的回路 思路:二分+判负环,每次二分一个值mid,判断是否存在小于mid的环,那么就是(w1 + w2 + w3...) / n < mid == w1 - mid + w2 - mid + w3 - mid .... < 0,所以每次二分的时候,把边权值减掉mid,之后bellmanford判负环即可 代码: #include <cstdio> #include <cst

UVA 11090 - Going in Cycle!!

二分+SPFA找负环 11090 - Going in Cycle!! Time limit: 3.000 seconds I I U P C 2 0 0 6 Problem G: Going in Cycle!! Input: standard input Output: standard output You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has

UVA - 11090 Going in Cycle!! (Bellman-Ford算法判负环)

Description I I U P C 2 0 06 Problem G: Going in Cycle!! Input: standard input Output: standard output You are given a weighted directed graph with n vertices and m edges. Each cycle in the graph has a weight, which equals to sum of its edges. There

poj Wormholes 【最短路径】【bellman_ford】

Wormholes Description While exploring his many farms, Farmer John has discovered a number of amazing wormholes. A wormhole is very peculiar because it is a one-way path that delivers you to its destination at a time that is BEFORE you entered the wor

uva 10154 - Weights and Measures【dp】qi

题意:uva 10154 - Weights and Measures 题意:有一些乌龟有一定的体重和力量,求摞起来的最大高度.力量必须承受其上面包括自己的全部的重量. 分析:先按其能举起来的力量从小到大排序 然后定义dp[i] 表示摞起来 i 只乌龟的最小质量. 然后转移就是每次用遍历O(n)的复杂度找最小的,然后记录,保存最大值即可. AC代码: #include<iostream> #include<cstdio> #include<cstring> #inclu

UVa 11090 Going in Cycle!! (Bellman_Ford)

题意:给定一个加权有向图,求平均权值最小的回路. 析:先十分答案,假设答案是 ans,那么有这么一个回路,w1+w2+w3+...+wk < k*ans,这样就是答案太大,然后移项可得,(w1-ans)+(w2-ans)+(w3-ans) + ..+(wk-ans) < 0,这样的话就判断是不是有负图就好了. 代码如下: #pragma comment(linker, "/STACK:1024000000,1024000000") #include <cstdio&g

HDU 2544 最短路【Bellman_Ford 】

题意:给出n个节点,m条边,问从起点到终点的最短距离 用bellman_ford,注意是无向图 初学bellman_ford= =一点点理解 因为dijkstra是每次用集合里面的点去更新它们所连接的点的距离 假设集合s={A}, 如果B能够被A“带”入集合的话,说明AB一定是最短的距离了,因为后来不管怎么样,边权都是正的,不会使得AB变得更小 所以,dijkstra只能处理正权图 然后Bellman_Ford可以处理负权,反复用已有的边来更新最短距离 从起点1到终点n的最短距离最多经过n-2个

UVA 11090 Going in Cycle!!(Bellman-Ford判断负圈)

题意:给定一个n个点m条边的加权有向图,求平均权值最小的回路. 思路:使用二分法求解,对于每一个枚举值mid,判断每条边权值减去mid后有无负圈即可. #include<cstdio> #include<cstring> #include<cmath> #include<cstdlib> #include<iostream> #include<algorithm> #include<vector> #include<

UVA 11090 Going in Cycle!! 环平均权值(bellman-ford,spfa,二分)

题意:给定一个n个点m条边的带权有向图,求平均权值最小的回路的平均权值? 思路:首先,图中得有环的存在才有解,其次再解决这个最小平均权值为多少.一般这种就是二分猜平均权值了,因为环在哪也难以找出来,还有可能是一条边属于多个环.对于每个猜到的平均值,如果对应环的存在,那么这个环的每条边的权减去这个平均值之后,用spfa算法就能判断其是否有环的存在即可. 假设环上各边权值为:w1+w2+...+wk. 式子:w1+w2+...+wk<k*even   相当于   (w1-even)+(w2-even