题意:给你一个有向图,问你定义一个环的平均值为这个环上所有边的平均值,问你最小的环的平均值是多少。
解题思路:我们可以[二分答案],再用[SPFA]来check。
check方法:设最小环有k条边,Wi为第i条边的边权,猜测值为mid,那么有
(W1+W2+…+Wk) / k < mid
(W1+W2+…+Wk) < mid * k
(W1-mid)+(W2-mid)+…+(Wk-mid)<0
我们把每一条边权值都减去mid,再判断图中是否出现了负环。
#include <queue>
#include <cstdio>
#include <cstring>
#include <algorithm>
#include <iostream>
#define Inf 100000000
using namespace std;
const int N = 55;
struct Edge{
int u, v;
double dist;
Edge(int u, int v, double dist):u(u),v(v),dist(dist){}
};
struct SPFA{
int n, m;
double d[N];
bool inq[N];
int cnt[N];
vector<Edge> edges;
vector<int> G[N];
void init(int n){
this->n=n;
for ( int i=1; i<=n; i++ ) G[i].clear();
edges.clear();
}
void addeage(int u, int v, double w){
edges.push_back(Edge(u,v,w));
m=edges.size();
G[u].push_back(m-1);
}
bool spfa(int s){
queue<int> Q;
for ( int i=1; i<=n; i++ ) d[i]=Inf, inq[i]=0, cnt[i]=0;
d[s]=0;
Q.push(s);
while( !Q.empty() ){
int u=Q.front(); Q.pop();
inq[u]=false;
for ( int i=0; i<G[u].size(); i++ ){
Edge& e=edges[G[u][i]];
if( d[e.v]>d[u]+e.dist ){
d[e.v]=d[u]+e.dist;
if( !inq[e.v] ){
inq[e.v]=1;
Q.push(e.v);
if( ++cnt[e.v]==n ) return true;
}
}
}
}
return false;
}
}S;
int n, m;
bool binary(double x){
for ( int i=0; i<S.m; i++ ) S.edges[i].dist-=x;
bool cnt=false;
for ( int i=1; i<=n; i++ )
if( S.spfa(i) ){
cnt=true;
break;
}
for ( int i=0; i<S.m; i++ ) S.edges[i].dist+=x;
return cnt;
}
int main(){
int T;
scanf("%d", &T);
for ( int k=1; k<=T; k++ ){
scanf("%d%d", &n, &m );
S.init(n);
double ub;
for ( int i=1; i<=m; i++ ){
int u, v;
double w;
scanf("%d%d%lf", &u, &v, &w );
ub=max(ub,w);
S.addeage(u,v,w);
}
printf("Case #%d: ", k);
if( !binary(ub+1.0) ) printf("No cycle found.\n");
else {
double L=0, R=ub;
while( R-L>1e-3 ){
double M = L+(R-L)/2;
if( binary(M) ) R=M;
else L=M;
}
printf("%.2lf\n", L);
}
}
}