uva11090(二分spfa)
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 a weight, which equals to sum of its edges. There are so many cycles in the graph with different weights. In this problem we want to find a cycle with the minimum mean.
|
|
Input |
|
The first line of input gives the number of cases, N. N test cases follow. Each one starts with two numbers n and m. m lines follow, each has three positive number a, b, c which means there is an edge from vertex a to b with weight of c.
|
|
Output |
|
For each test case output one line containing “Case #x: ” followed by a number that is the lowest mean cycle in graph with 2 digits after decimal place, if there is a cycle. Otherwise print “No cycle found.”.
|
|
Constraints |
|
- n ≤ 50 - a, b ≤ n - c ≤ 10000000
|
|
Sample Input |
Output for Sample Input |
2 |
题目大意:给定n个点m条边的加权有向图,求平均权值最小的回路
大体思路:使用二分法求解,对于每一个猜测值mid,只需要判断是否存在平均值小于mid的回路。如何判断呢?假设存在一个包含K条边的回路,回路上个条边的权值为w1,w2
,,wk,那么平均值小于mid意味着w1+w2+w3+.....<K*mid即:(w1-mid)+(w2-mid)+(w3-mid)+....+(wk-mid)<0;换句话说,只要把每条边(a,b)的权值w(a,b)换成w(a,b)-mid,再判断是否有负权的回路即可。
#include <iostream> #include <stdio.h> #include <stdlib.h> #include<string.h> #include<algorithm> #include<math.h> #include<queue> using namespace std; typedef long long ll; double dis[100]; int cnt[100],m,n; bool vis[100]; const int N=100; int head[N]; int ip; struct edgenode { int to; double w; int next; } tu[N*N]; void add(int u,int v,int w) { tu[ip].to=v,tu[ip].w=w,tu[ip].next=head[u],head[u]=ip++; } bool spfa() { queue<int>q; for(int i=1; i<=n; i++) dis[i]=0,cnt[i]=0,vis[i]=1,q.push(i); while(!q.empty()) { int t=q.front(); q.pop(); vis[t]=0; for(int k=head[t]; k!=-1; k=tu[k].next) if(dis[t]+tu[k].w<dis[tu[k].to]) { dis[tu[k].to]=dis[t]+tu[k].w; if(!vis[tu[k].to]) { vis[tu[k].to]=1; q.push(tu[k].to); if(++cnt[tu[k].to]>=n) return 0; } } } return 1; } bool judge(double x) { bool flag=0; for(int i=1; i<=n; i++) for(int k=head[i]; k!=-1; k=tu[k].next) tu[k].w-=x; if(!spfa())flag=1; for(int i=1; i<=n; i++) for(int k=head[i]; k!=-1; k=tu[k].next) tu[k].w+=x; return flag; } int main() { int t,o=1; cin>>t; while(t--) { ip=0; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); memset(tu,-1,sizeof(tu)); double l=999999999,r=0,mid; while(m--) { int a,b; double w; scanf("%d%d%lf",&a,&b,&w); add(a,b,w); l=min(l,w); r=max(r,w); } printf("Case #%d: ",o++); if(!judge(r+1)) printf("No cycle found.\n"); else { double s=1e-8; while((r-l)>s) { mid=(r+l)/2.0; if(judge(mid)) r=mid; else l=mid; } printf("%.2lf\n",r); } } return 0; }