[SCOI2014]方伯伯运椰子

时间:2021-09-15 09:45:13

嘟嘟嘟

 

01分数规划思维题。

题中要求交通总量不减少,那么如果总量增加的话,总费用就会增加,所以一定不是更优的解。那么总量守恒。

这是不是就想到了网络流?对于每一个节点流入量等于流出量。然后就是很有思维的一个转化了:把压缩看成退流,把扩容看成增广。

边(x, y)一次压缩,就建一条y -> x,容量为a - d的边。

边(x, y)一次增广,就建一条x -> y,容量为b + d的边。也就是一次调整多出来的费用。那么这样建完图后,图中的一个环就代表一种调整方案!

回头看题,让求某一个比值最小,那一定会想到01分数规划,令ans = max((X - Y) / k),那么ans >= (X - Y) / k,于是有ans * k + Y - X >= 0。按上述的建图,Y - X就是环上的边权和,k就是环中的点数(边数),所以这个式子相当于每经过一条边,这条边的边权就加一个ans,那么ans * k + Y - X >= 0就可以写成Σ(ans + ei) >= 0。二分的时候,如果存在负环,说明mid取小了,向右二分;否则向左二分。

 

[SCOI2014]方伯伯运椰子[SCOI2014]方伯伯运椰子
 1 #include<cstdio>
 2 #include<iostream>
 3 #include<cmath>
 4 #include<algorithm>
 5 #include<cstring>
 6 #include<cstdlib>
 7 #include<cctype>
 8 #include<vector>
 9 #include<stack>
10 #include<queue>
11 using namespace std;
12 #define enter puts("") 
13 #define space putchar(' ')
14 #define Mem(a, x) memset(a, x, sizeof(a))
15 #define rg register
16 typedef long long ll;
17 typedef double db;
18 const int INF = 0x3f3f3f3f;
19 const db eps = 1e-8;
20 const int maxn = 5e3 + 5;
21 const int maxe = 3e3 + 5;
22 inline ll read()
23 {
24   ll ans = 0;
25   char ch = getchar(), last = ' ';
26   while(!isdigit(ch)) {last = ch; ch = getchar();}
27   while(isdigit(ch)) {ans = ans * 10 + ch - '0'; ch = getchar();}
28   if(last == '-') ans = -ans;
29   return ans;
30 }
31 inline void write(ll x)
32 {
33   if(x < 0) x = -x, putchar('-');
34   if(x >= 10) write(x / 10);
35   putchar(x % 10 + '0');
36 }
37 
38 int n, m;
39 struct Edge
40 {
41   int nxt, to, w;
42 }e[maxe << 1];
43 int head[maxn], ecnt = -1;
44 void addEdge(int x, int y, int w)
45 {
46   e[++ecnt] = (Edge){head[x], y, w};
47   head[x] = ecnt;
48 }
49 
50 db dis[maxn];
51 bool vis[maxn], mak[maxn];
52 bool spfa(int now, db x)
53 {
54   vis[now] = mak[now] = 1;
55   for(int i = head[now]; i != -1; i = e[i].nxt)
56     {
57       if(dis[e[i].to] > dis[now] + e[i].w + x)
58     {
59       dis[e[i].to] = dis[now] + e[i].w + x;
60       if(vis[e[i].to]) return 1;
61       if(spfa(e[i].to, x)) return 1;
62     }
63     }
64   vis[now] = 0;
65   return 0;
66 }
67 
68 bool judge(db x)
69 {
70   Mem(vis, 0); Mem(mak, 0);
71   for(int i = 1; i <= n + 2; ++i)
72     if(!mak[i])
73       {
74     if(spfa(i, x)) return 1;
75       }
76   return 0;
77 }
78 
79 int main()
80 {
81   Mem(head, -1);
82   n = read(); m = read();
83   for(int i = 1; i <= m; ++i)
84     {
85       int x = read(), y = read(), a = read(), b = read(), c = read(), d = read();
86       if(c) addEdge(y, x, a - d);
87       addEdge(x, y, b + d);
88     }
89   db L = 0, R = 1e5;
90   while(R - L > eps)
91     {
92       db mid = (L + R) / 2.00;
93       if(judge(mid)) L = mid;
94       else R = mid;
95     }
96   printf("%.2lf\n", L);
97   return 0;
98 }
View Code