给一个带权有向图,求其中是否存在环,若存在,输出环上边权的平均值最小的那个的平均值。
点的范围就50,感觉可以很暴力。。但显然超时了
感觉方法好巧妙,二分平均值,将所有边权减去二分的那个值,然后spfa判断是否有负环
若有负环,则图中存在的所有环的边权平均值一定比枚举值大
反之则小,要是无论枚举值多大都没有负环,说明图中没有环。
#include <iostream> #include <cstring> #include <string> #include <cstdio> #include <cmath> #include <algorithm> #include <vector> #include <queue> #include <map> #define inf 0x3f3f3f3f #define eps 1e-6 #define ll __int64 using namespace std; struct node { int v,next; double w; }e[10000]; double d[110]; int inq[110],outq[110],head[110],h,n,m; void init() { memset(head,-1,sizeof head); h=0; } void addedge(int a,int b,double c) { e[h].v=b; e[h].w=c; e[h].next=head[a]; head[a]=h++; } int spfa(int st,double cut) { for(int i=0;i<=n;i++) d[i]=1e15; memset(inq,0,sizeof inq); memset(outq,0,sizeof outq); d[st]=0;inq[st]=1; queue<int> q; q.push(st); while(!q.empty()) { int x=q.front(); q.pop(); inq[x]=0; outq[x]++; if(outq[x]>n) return 0;//存在负环//是在与源点连通的图上有负环 for(int i=head[x];i!=-1;i=e[i].next) { if(d[e[i].v]>d[x]+e[i].w-cut) { d[e[i].v]=d[x]+e[i].w-cut; if(!inq[e[i].v]) { inq[e[i].v]=1; q.push(e[i].v); } } } } return 1; } int main() { int a,b,i,t,T=1; double c,mid,ri,le; scanf("%d",&t); while(t--) { printf("Case #%d: ",T++); init(); scanf("%d%d",&n,&m); double mmax=0; while(m--) { scanf("%d%d%lf",&a,&b,&c); addedge(a,b,c); mmax=max(mmax,c); } /*if(spfa(1,mmax+1))//判断是否连通//这里源点只有1 { printf("No cycle found.\n"); continue; }*/ le=0;ri=mmax+5; while(ri-le>eps) { // printf("le:%lf ri:%lf\n",le,ri); int flag=0; mid=(ri+le)*0.5; for(i=1;i<=n;i++)//wa... { if(!spfa(i,mid)) { flag=1; break; } } if(!flag) le=mid; else ri=mid; } if(ri==mmax+5) printf("No cycle found.\n"); else printf("%.2lf\n",ri); } return 0; }
uva11090 Going in Cycle!! --- 二分+spfa判负环
时间: 2024-10-05 05:00:36