题意:
在一个有向图中找一个平均距离最小的环。
思路:
二分枚举平均最小距离,每次每条边减去这个距离,然后spfa(或者bellmanFord找负环)假设找到,说明平均最小距离比这个值要小。假设没找到。则说明平均最小距离比这个值大。
注意可能是不连通图~
代码:
#include <iostream> #include <cstdio> #include <cstring> #include <queue> #define INF 0x3f3f3f3f #define eps 1e-6 #define maxn 55 #define MAXN 10005 using namespace std; int n,m,ans,cnt,sx; double le,ri,mid,res; bool vis[maxn]; double dist[maxn]; int head[maxn],num[maxn]; struct Node { int v,next; double w; }edge[MAXN]; void addedge(int u,int v,double w) { cnt++; edge[cnt].v=v; edge[cnt].w=w; edge[cnt].next=head[u]; head[u]=cnt; } bool SPFA(int k) { int i,j,nx,v; memset(vis,0,sizeof(vis)); memset(num,0,sizeof(num)); for(i=1;i<=n;i++) dist[i]=INF; sx=k; queue<int>q; dist[sx]=0; vis[sx]=num[sx]=1; q.push(sx); while(!q.empty()) { nx=q.front(); vis[nx]=0; q.pop(); for(i=head[nx];i;i=edge[i].next) { v=edge[i].v; if(dist[v]>dist[nx]+edge[i].w-mid) { dist[v]=dist[nx]+edge[i].w-mid; if(!vis[v]) { num[v]++; if(num[v]>n) return true ; vis[v]=1; q.push(v); } } } } return false ; } int main() { int i,j,u,v,t,test=0; double w; scanf("%d",&t); while(t--) { scanf("%d%d",&n,&m); cnt=0; memset(head,0,sizeof(head)); for(i=1;i<=m;i++) { scanf("%d%d%lf",&u,&v,&w); addedge(u,v,w); } le=0; ri=10000005; int flag; while(ri-le>eps) { mid=(le+ri)/2.0; flag=0; for(i=1;i<=n;i++) { if(SPFA(i)) { flag=1; break ; } } if(flag) ri=mid; else le=mid; } res=le; if(res<=10000001) printf("Case #%d: %.2f ",++test,res); else printf("Case #%d: No cycle found. ",++test); } return 0; }