题目大意:一个n个点,m条无向边的图,求出平均权值最小的回路。
题目分析:二分枚举平均值mid,只需判断是否存在平均值小于mid的回路,即判断是否有sum(wi)<mid*k (1≤i≤k),只需判断是否有sum(wi-mid)<0,只需将边权值减去mid后,判断是否存在负环。
代码如下:
# include<iostream> # include<cstdio> # include<queue> # include<vector> # include<cstring> # include<algorithm> using namespace std; const double inf=1e30; struct Edge { int to,nxt; double w; }; Edge e[10000]; double dist[55]; int vis[55],inq[55],head[55],n,cnt; void add(int u,int v,double w) { e[cnt].to=v; e[cnt].w=w; e[cnt].nxt=head[u]; head[u]=cnt++; } bool judge(double M) { queue<int>q; memset(vis,0,sizeof(vis)); memset(inq,0,sizeof(inq)); for(int i=0;i<n;++i){ dist[i]=0; vis[i]=inq[i]=1; q.push(i); } while(!q.empty()) { int u=q.front(); q.pop(); inq[u]=0; for(int i=head[u];i!=-1;i=e[i].nxt){ if(dist[e[i].to]>dist[u]+e[i].w-M){ dist[e[i].to]=dist[u]+e[i].w-M; if(!inq[e[i].to]){ q.push(e[i].to); inq[e[i].to]=1; if(++vis[e[i].to]>n) return true; } } } } return false; } int main() { int T,m,a,b,c,cas=0; scanf("%d",&T); while(T--) { cnt=0; memset(head,-1,sizeof(head)); scanf("%d%d",&n,&m); int maxn=0; while(m--) { scanf("%d%d%d",&a,&b,&c); add(--a,--b,c+0.0); maxn=max(maxn,c); } printf("Case #%d: ",++cas); if(!judge(maxn+1.0)){ printf("No cycle found. "); continue; } double l=0.0,r=(double)maxn; while(r-l>1e-3){ double m=l+(r-l)/2; if(judge(m)) r=m; else l=m; } printf("%.2lf ",l); } return 0; }