BZOJ1486:[HNOI2009]最小圈(最短路,二分)
Description
Input
Output
Sample Input
4 5
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
1 2 5
2 3 5
3 1 5
2 4 3
4 1 3
Sample Output
3.66666667
Solution
二分一个$ans$,然后每条边减去$ans$,若存在负环则$ans$合法。
判断个入队20次就很稳了。
Code
1 #include<iostream> 2 #include<cstring> 3 #include<cstdio> 4 #include<queue> 5 #define N (3009) 6 using namespace std; 7 8 double eps=1e-9,dis[N]; 9 struct Edge{int to,next,len;}edge[N*10]; 10 int n,m,u,v,l,cnt[N],used[N],head[N],num_edge; 11 queue<int>q; 12 13 void add(int u,int v,int l) 14 { 15 edge[++num_edge].to=v; 16 edge[num_edge].len=l; 17 edge[num_edge].next=head[u]; 18 head[u]=num_edge; 19 } 20 21 bool SPFA(double mid) 22 { 23 memset(cnt,0,sizeof(cnt)); 24 memset(used,0,sizeof(used)); 25 for (int i=1; i<=n; ++i) dis[i]=1e18; 26 while (!q.empty()) q.pop(); 27 dis[1]=0; used[1]=true; q.push(1); 28 while (!q.empty()) 29 { 30 int x=q.front(); q.pop(); 31 for (int i=head[x]; i; i=edge[i].next) 32 if (dis[x]+edge[i].len-mid<dis[edge[i].to]) 33 { 34 dis[edge[i].to]=dis[x]+edge[i].len-mid; 35 if (!used[edge[i].to]) 36 { 37 cnt[edge[i].to]++; 38 if (cnt[edge[i].to]>20) return true; 39 used[edge[i].to]=true; 40 q.push(edge[i].to); 41 } 42 } 43 used[x]=false; 44 } 45 return false; 46 } 47 48 int main() 49 { 50 scanf("%d%d",&n,&m); 51 for (int i=1; i<=m; ++i) 52 scanf("%d%d%d",&u,&v,&l),add(u,v,l); 53 double l=-1e7, r=1e7; 54 while (r-l>eps) 55 { 56 double mid=(l+r)/2; 57 if (SPFA(mid)) r=mid; 58 else l=mid; 59 } 60 printf("%.8lf\n",l); 61 }