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 }