思路:二分平均值,运用spfa算法判负环
#include <iostream>
#include <cstring>
#include <stdio.h>
#include <queue>
#define INF 0x3f3f3f3f
using namespace std;
double p=1e-8;
int n,m;
double l,r;
int v[3000],u[3000],vis[3000],first[3000],nex[3000],num[3000];
double w[3000],d[3000];
int e;
void add(int a,int b,int c)
{
v[e]=b;
u[e]=a;
w[e]=(double)c;
nex[e]=first[a];
first[a]=e++;
}
int spfa()
{
queue <int> q;
//memset(num,0,sizeof(num));
//memset(vis,0,sizeof(vis));
for(int i=1;i<=n;i++)
{
q.push(i);
vis[i]=1;
num[i]=0;
d[i]=0;
}
//vis[1]=1;
while(!q.empty())
{
int tmp=q.front();
q.pop();
vis[tmp]=0;
for(int i=first[tmp];i!=-1;i=nex[i])
{
if(d[v[i]]>d[tmp]+w[i])
{
d[v[i]]=d[tmp]+w[i];
if(!vis[v[i]])
{
q.push(v[i]);
vis[v[i]]=1;
if(num[v[i]]++>n)
return 1;
}
}
}
}
return 0;
}
int judge(double x)
{
int flag=0;
for(int i=0;i<e;i++)
w[i]-=x;
if(spfa())
flag=1;
for(int i=0;i<e;i++)
w[i]+=x;
return flag;
}
int main()
{
//freopen("in.txt","r",stdin);
int t;
scanf("%d",&t);
int ans=1;
while(t--)
{
scanf("%d%d",&n,&m);
int a,b,c;
e=0;
l=INF,r=-INF;
memset(first,-1,sizeof(first));
memset(w,0,sizeof(w));
for(int i=0;i<m;i++)
{
scanf("%d%d%d",&a,&b,&c);
add(a,b,c);
l=min((double)c,l);
r=max(r,(double)c);
}
double mid;
printf("Case #%d: ",ans++);
if(!judge(r+1))
{
printf("No cycle found.\n");
}
else
{
while(r-l>p)
{
mid=(double)(r+l)/2;
if(judge(mid))
r=mid;
else
l=mid;
}
printf("%.2lf\n",l);
}
}
}