1. 程式人生 > >【洛谷P3199】[HNOI2009]最小圈

【洛谷P3199】[HNOI2009]最小圈

turn bsp pri 如果 其中 als pre sin def

題目描述

對於一張有向圖,要你求圖中最小圈的平均值最小是多少,即若一個圈經過k個節點,那麽一個圈的平均值為圈上k條邊權的和除以k,現要求其中的最小值。

輸入輸出格式

輸入格式:

第一行2個正整數,分別為n和m

以下m行,每行3個數,表示邊連接的信息,

輸出格式:

一行一個數,表示最小圈的值,保留8位小數。

說明

若設邊權為v,那麽50000n≤3000,m≤10000,v≤50000。

分析

此題要求最小圈平均值最小是多少。如果這個圈的平均值是負數那麽這就是一個負環。判斷負環可以用spfa,然後用二分答案做就行了。

代碼

#include<iostream>
#include
<cstdio> #include<cstring> #include<algorithm> using namespace std; typedef double db; const int maxn=3005; const int maxm=10005; const db eps=1e-10; inline void read(int &x){ x=0; char ch=getchar(); while(ch<0||ch>9) ch=getchar(); while(ch>=0&&ch<=
9){x=(x<<1)+(x<<3)+(ch^48);ch=getchar();} } int n,m,tot; int head[maxn]; double dis[maxn]; bool vis[maxn]; struct node{ int next,to,dist; }e[maxm<<1]; inline void ins(int from,int to,int dist){ e[++tot].next=head[from]; e[tot].to=to; e[tot].dist=dist; head[
from]=tot; } bool spfa(int x,db lim){ vis[x]=true; for(int i=head[x];i;i=e[i].next){ int to=e[i].to; if(dis[to]>dis[x]+(db)e[i].dist-lim){ if(vis[to]) return true; else{ dis[to]=dis[x]+(db)e[i].dist-lim; if(spfa(to,lim)) return true; } } } return vis[x]=false; } inline bool pd(double lim){ memset(vis,0,sizeof(vis)); memset(dis,0,sizeof(dis)); for(int i=1;i<=n;++i) if(spfa(i,lim)) return true; return false; } int main(){ read(n);read(m); for(int i=1;i<=m;++i){ int u,v,w; read(u);read(v);read(w); ins(u,v,w); } db l=0.0,r=50000.0,mid; while(r-l>eps){ mid=(l+r)/2.0; if(pd(mid)) r=mid; else l=mid; } printf("%.8lf",r); return 0; }

【洛谷P3199】[HNOI2009]最小圈