BZOJ1486:[HNOI2009]最小圈(最短路,二分)

Description

Input

Output

Sample Input

4 5
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
",l);
61 }
原文地址:https://www.cnblogs.com/refun/p/9777965.html