- 题目大意
给你一个有向图,问你定义一个环的平均值为这个环上所有边的平均值,问你最小的环的平均值是多少。
- 解题思路
先利用spfa来判断负环,然后用二分去判断若当前的二分值是mid,让所有的边都减去这个值,如果此时图中出现负环,则说明有环的平均值比这个更小。
- 代码
#include<cstdio> #include<algorithm> #include<queue> #include<vector> #include<cstring> using namespace std; const int N=500; const int M=1e6+5; const int INF=0x3f3f3f; int n,m; struct edge { int v,next; double w; }e[M*2]; int head[N], cnt; double d[N]; int inq[N]; int cn[N]; void init () { cnt=0; memset(head,-1,sizeof(head)); } void addedge(int u,int v,double c) { e[cnt].w=c; e[cnt].v=v; e[cnt].next=head[u]; head[u]=cnt++; } bool SPFA(int s) { memset(d, INF, sizeof(d)); memset(inq, 0, sizeof(inq)); memset(cn, 0, sizeof(cn)); queue<int> Q; Q.push(s); d[s] = 0; inq[s] = 1; while(Q.size()) { int u = Q.front(); Q.pop(); inq[u] = 0; for(int i = head[u]; ~i; i = e[i].next) { int v = e[i].v; double w = e[i].w; if(d[v] > d[u] + w) { d[v] = d[u] + w; if(!inq[v]) { Q.push(v); inq[v] = 1; if(++cn[v] >= n) return false; } } } } return true; } bool check(double x) { bool vis=false; for(int i=1;i<=n;i++) { for(int j=head[i];j!=-1;j=e[j].next) e[j].w-=x; } for(int i=1;i<=n;i++) { if(!SPFA(i)) vis=true; } for(int i=1;i<=n;i++) { for(int j=head[i];j!=-1;j=e[j].next) e[j].w+=x; } return vis; } int main() { int t,a,b; double c; scanf("%d",&t); for(int k=1;k<=t;k++) { double l=INF,r=0,mid; init(); scanf("%d%d",&n,&m); for(int i=1;i<=m;i++) { scanf("%d%d%lf",&a,&b,&c); addedge(a,b,c); l=min(l,c); r=max(r,c); } printf("Case #%d: ",k); if(!check(r+1)) printf("No cycle found.\n"); else { while(r-l>1e-8) { mid=(r+l)/2; if(check(mid)) r=mid; else l=mid; } printf("%.2lf\n",r); } } return 0; }