平均值最小回路
二分答案后把每条边的权值都减去答案
然后spfa判负圈
果断TLE
参照09年论文改成DFS版的SPFA,AC
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
#include<cmath>
using namespace std;
const int N=3000+5;
const int M=10000+5;
const double eps=1e-9;
struct Edge{int to,next;double v;}e[M];
int head[N],cnt;
void ins(int u,int v,double w){
e[++cnt]=(Edge){v,head[u],w};head[u]=cnt;
}
double d[N];
bool inq[N];
int n,m;
bool spfa(int u){
inq[u]=1;
for(int i=head[u];i;i=e[i].next){
int v=e[i].to;
if(d[v]>d[u]+e[i].v){
if(inq[v])return true;
else{
d[v]=d[u]+e[i].v;
if(spfa(v))return true;
}
}
}
inq[u]=0;
return false;
}
bool check(){
for(int i=1;i<=n;i++)
if(spfa(i))return true;
return false;
}
bool check(double x){
memset(d,0,sizeof(d));
memset(inq,0,sizeof(inq));
for(int i=1;i<=cnt;i++)e[i].v-=x;
bool ans=check();
for(int i=1;i<=cnt;i++)e[i].v+=x;
return ans;
}
int main(){
//freopen("a.in","r",stdin);
scanf("%d%d",&n,&m);
double l=1e60,r=-(1e60);
while(m--){
int u,v;double w;
scanf("%d%d%lf",&u,&v,&w);
ins(u,v,w);
l=min(l,w);
r=max(r,w);
}
while(r-l>1e-9){
double mid=(l+r)/2.0;
if(check(mid))r=mid;
else l=mid;
}
printf("%.8lf\n",l);
return 0;
}