平均值最小回路
二分答案后把每条边的权值都减去答案
然后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; }