给一个带权有向图,求其中是否存在环,若存在,输出环上边权的平均值最小的那个的平均值。
点的范围就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;
}