P3199 [HNOI2009]最小圈

原题链接

考察:01分数规划+SPFA

思路:

        基本是和观光奶牛一样的题,这题的边权化为 sgma(w[i]) - mid.然后判断是否存在负环.

        但是会TLE 5个点,此时可以用玄学优化,如果已经转了5圈就说明存在负环.

 1 #include <iostream> 
 2 #include <cstring>
 3 #include <algorithm>
 4 #include <queue>
 5 using namespace std;
 6 const int N = 3010,M = 10010;
 7 const double eps = 1e-10;
 8 int h[N],idx,n,m,cnt[N];
 9 double dist[N];
10 bool st[N];
11 struct Road{
12     int fr,to,ne;
13     double w;
14 }road[M];
15 void add(int a,int b,double c)
16 {
17     road[idx].fr = a,road[idx].to = b,road[idx].ne = h[a],road[idx].w = c,h[a] = idx++;
18 }
19 bool check(double mid)
20 {
21     queue<int> q;
22     int count = 0;
23     for(int i=1;i<=n;i++) q.push(i),st[i] = 1,dist[i] = 0,cnt[i] = 0;
24     while(q.size())
25     {
26         int u = q.front();
27         q.pop();
28         st[u] = 0;
29         for(int i=h[u];~i;i=road[i].ne)
30         {
31             int v = road[i].to;
32             if(dist[v]>dist[u]+road[i].w-mid)
33             {
34                 dist[v] = dist[u]+road[i].w-mid;
35                 cnt[v] = cnt[u]+1;
36                 count++;
37                 if(count>=5*n) return 1;
38                 if(cnt[v]>=n) return 1;
39                 if(!st[v]) q.push(v),st[v] = 1;
40             }
41         }
42     }
43     return 0;
44 }
45 int main()
46 {
47     scanf("%d%d",&n,&m);
48     double l = 0,r = 0;
49     memset(h,-1,sizeof h);
50     while(m--)
51     {
52         int a,b; double c;
53         scanf("%d%d%lf",&a,&b,&c);
54         add(a,b,c);
55         r += max(0.0,c); l+=min(0.0,c);
56     }
57     while(r-l>=eps)
58     {
59         double mid = (l+r)/2;
60         if(check(mid)) r = mid;
61         else l = mid;
62     }
63     printf("%.8lf\n",r);
64     return 0;
65 }

 

posted @ 2021-05-06 18:13  acmloser  阅读(35)  评论(0编辑  收藏  举报