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;
}