1. 程式人生 > >bzoj 3597 [Scoi2014] 方伯伯運椰子 - 費用流 - 二分答案

bzoj 3597 [Scoi2014] 方伯伯運椰子 - 費用流 - 二分答案

題目傳送門

  傳送門

題目大意

  給定一個費用流,每條邊有一個初始流量$c_i$和單位流量費用$d_i$,增加一條邊的1單位的流量需要花費$b_i$的代價而減少一條邊的1單位的流量需要花費$a_i$的代價。要求最小化總費用減少量和調整次數的比值(至少調整一次)。

  根據基本套路,二分答案,移項,可以得到每條邊的貢獻。

  設第$i$條邊的流量變化量為$m_i$,每次變化花費的平均費用為$w_i$。那麼有

$\sum c_id_i - \sum (c_i + m_i)d_i + |m_i|(w_i + mid) > 0$

$\sum m_id_i+ |m_i|(w_i + mid) < 0$

  那麼二分答案後等於判斷是否存在一個增廣環的費用和為負。(請手動參見式子腦補邊權)。

  然後可以寫個spfa。

Code

  1 /**
  2  * bzoj
  3  * Problem#3597
  4  * Accepted
  5  * Time: 464ms
  6  * Memory: 1720k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #include <vector>
 12
#include <queue> 13 using namespace std; 14 typedef bool boolean; 15 16 template <typename T> 17 void pfill(T* pst, const T* ped, T val) { 18 for ( ; pst != ped; *(pst++) = val); 19 } 20 21 typedef class Edge { 22 public: 23 int ed, nx; 24 double
w; 25 26 Edge(int ed, int nx, double w) : ed(ed), nx(nx), w(w) { } 27 } Edge; 28 29 typedef class MapManager { 30 public: 31 int* h; 32 vector<Edge> es; 33 34 MapManager() { } 35 MapManager(int n) { 36 h = new int[(n + 1)]; 37 pfill(h, h + n + 1, -1); 38 } 39 ~MapManager() { 40 delete[] h; 41 es.clear(); 42 } 43 44 void addEdge(int u, int v, double w) { 45 es.push_back(Edge(v, h[u], w)); 46 h[u] = (signed) es.size() - 1; 47 } 48 49 Edge& operator [] (int p) { 50 return es[p]; 51 } 52 } MapManager; 53 54 const double dinf = 1e10; 55 const double eps = 1e-4; 56 57 typedef class Graph { 58 public: 59 int n, s; 60 MapManager g; 61 62 int *cnt; 63 double *f; 64 boolean *vis; 65 66 Graph(int n, int s) : n(n), s(s), g(n) { 67 cnt = new int[(n + 1)]; 68 f = new double[(n + 1)]; 69 vis = new boolean[(n + 1)]; 70 pfill(vis, vis + n + 1, false); 71 } 72 73 boolean neg_circle() { 74 static queue<int> que; 75 pfill(f, f + n + 1, dinf); 76 pfill(cnt, cnt + n + 1, 0); 77 f[s] = 0, cnt[s]++; 78 que.push(s); 79 while (!que.empty()) { 80 int e = que.front(); 81 que.pop(); 82 vis[e] = false; 83 for (int i = g.h[e], eu; ~i; i = g[i].nx) { 84 eu = g[i].ed; 85 double w = f[e] + g[i].w; 86 if (w < f[eu]) { 87 f[eu] = w, cnt[eu]++; 88 if (cnt[eu] > n) 89 return true; 90 if (!vis[eu]) { 91 que.push(eu); 92 vis[eu] = true; 93 } 94 } 95 } 96 } 97 return false; 98 } 99 } Graph; 100 101 int n, m; 102 int *u, *v, *a, *b, *c, *d; 103 double init_ans = 0.0; 104 105 inline void init() { 106 scanf("%d%d", &n, &m); 107 u = new int[(m + 1)]; 108 v = new int[(m + 1)]; 109 a = new int[(m + 1)]; 110 b = new int[(m + 1)]; 111 c = new int[(m + 1)]; 112 d = new int[(m + 1)]; 113 for (int i = 1; i <= m; i++) { 114 scanf("%d%d%d%d%d%d", u + i, v + i, a + i, b + i, c + i, d + i); 115 init_ans += c[i] * d[i]; 116 } 117 } 118 119 boolean check(double mid) { 120 Graph graph(n + 2, n + 1); 121 MapManager& g = graph.g; 122 123 for (int i = 1; i <= m; i++) { 124 if (u[i] == n + 1) { 125 g.addEdge(u[i], v[i], 0); 126 } else if (c[i]) { 127 g.addEdge(u[i], v[i], d[i] + b[i] + mid); 128 g.addEdge(v[i], u[i], -d[i] + a[i] + mid); 129 } else { 130 g.addEdge(u[i], v[i], d[i] + b[i] + mid); 131 } 132 } 133 134 return graph.neg_circle(); 135 } 136 137 inline void solve() { 138 double l = 0, r = init_ans, mid; 139 for (int t = 0; t < 128 && l < r - eps; t++) { 140 mid = (l + r) / 2; 141 if (check(mid)) 142 l = mid; 143 else 144 r = mid; 145 } 146 printf("%.2lf\n", l); 147 } 148 149 int main() { 150 init(); 151 solve(); 152 return 0; 153 }
spfa

  然後再講講費用流做法。因為不存在負的流量,但是我們知道$c_i' \geqslant 0$,因此我們考慮將$m_i$變成$-c_i + m_i'$。

  其中$m_i'$始終非負。可以理解為這個做法就是將所有邊的流量先變為0再重新調整。

  對於絕對值的部分稍微處理一下就行了。(之前那個式子腦殘取了等,調了半天,sad。。。)

Code

  1 /**
  2  * bzoj
  3  * Problem#3597
  4  * Accepted
  5  * Time: 1168ms
  6  * Memory: 2004k
  7  */
  8 #include <iostream>
  9 #include <cstdlib>
 10 #include <cstdio>
 11 #include <queue>
 12 #include <cmath>
 13 using namespace std;
 14 typedef bool boolean;
 15 
 16 template <typename T>
 17 void pfill(T* pst, const T* ped, T val) {
 18     for ( ; pst != ped; *(pst++) = val);
 19 }
 20 
 21 typedef class Edge {
 22     public:
 23         int ed, nx, r;
 24         double c;
 25 
 26         Edge(int ed = 0, int nx = 0, int r = 0, double c = 0) : ed(ed), nx(nx), r(r), c(c) {    } 
 27 } Edge;
 28 
 29 typedef class MapManager {
 30     public:
 31         int* h;
 32         vector<Edge> es;
 33 
 34         MapManager() {    }
 35         MapManager(int n) {
 36             h = new int[(n + 1)];
 37             pfill(h, h + n + 1, -1);
 38         }
 39         ~MapManager() {
 40             delete[] h;
 41             es.clear();
 42         }
 43 
 44         void addEdge(int u, int v, int r, double c) {
 45             es.push_back(Edge(v, h[u], r, c));
 46             h[u] = (signed) es.size() - 1;
 47         }
 48 
 49         void addArc(int u, int v, int cap, double c) {
 50             addEdge(u, v, cap, c);
 51             addEdge(v, u, 0, -c);
 52         }
 53 
 54         Edge& operator [] (int p) {
 55             return es[p];
 56         }
 57 } MapManager;
 58 
 59 const signed int inf = (signed) (~0u >> 1);
 60 const double dinf = 1e10;
 61 const double eps = 1e-4;
 62 
 63 template <typename T>
 64 T __abs(T x) {
 65     return (x < 0) ? (-x) : (x);
 66 }
 67 
 68 typedef class Network {
 69     public:
 70         int S, T;
 71         MapManager g;
 72         
 73         int *le;
 74         int *mf;
 75         double *f;
 76         boolean *vis;
 77 
 78         Network() {    }
 79         // be sure T is the last node
 80         Network(int S, int T) : S(S), T(T), g(T) {
 81             f = new double[(T + 1)];
 82             le = new int[(T + 1)];
 83             mf = new int[(T + 1)];
 84             vis = new boolean[(T + 1)];
 85             pfill(vis, vis + T, false);
 86         }
 87         ~Network() {
 88             delete[] f;
 89             delete[] le;
 90             delete[] mf;
 91             delete[] vis;
 92         }
 93 
 94         double spfa() {
 95             double w;
 96             static queue<int> que;
 97             pfill(f, f + T + 1, dinf);
 98             que.push(S);
 99             f[S] = 0, le[S] = -1, mf[S] = inf;
100             while (!que.empty()) {
101                 int e = que.front();
102                 que.pop();
103                 vis[e] = false; 
104                 for (int i = g.h[e], eu; ~i; i = g[i].nx) {
105                     if (!g[i].r)
106                         continue;
107                     eu = g[i].ed, w = f[e] + g[i].c;
108                     if (w < f[eu]) {
109                         f[eu] = w, le[eu] = i, mf[eu] = min(mf[e], g[i].r);
110                         if (!vis[eu]) {
111                             vis[eu] = true;
112                             que.push(eu);
113                         }
114                     }
115                 }
116             }
117             if (__abs(f[T] - dinf) < eps)
118                 return dinf;
119             double rt = 0;
120             for (int p = T, e; ~le[p]; p = g[e ^ 1].ed) {
121                 e = le[p];
122                 g[e].r -= mf[T];
123                 g[e ^ 1].r += mf[T];
124                 rt += mf[T] * g[e].c;
125             }
126             return rt;
127         }
128 
129         double min_cost() {
130             double rt = 0, delta;
131             while (__abs((delta = spfa()) - dinf) >= eps) {
132                 rt += delta;
133             }
134             return rt;
135         }
136 } Network;
137 
138 // S: n + 1, T: n + 2
139 int n, m;
140 int *u, *v, *a, *b, *c, *d;
141 double init_ans = 0.0;
142 
143 inline void init() {
144     scanf("%d%d", &n, &m);
145     u = new int[(m + 1)];
146     v = new int[(m + 1)];
147     a = new int[(m + 1)];
148     b = new int[(m + 1)];
149     c = new int[(m + 1)];
150     d = new int[(m + 1)];
151     for (int i = 1; i <= m; i++) {
152         scanf("%d%d%d%d%d%d", u + i, v + i, a + i, b + i, c + i, d + i);
153         init_ans += c[i] * d[i];
154     }
155 }
156 
157 boolean check(double mid) {
158     double cost = 0;
159     Network network(n + 1, n + 2);
160     MapManager& g = network.g;
161     for (int i = 1; i <= m; i++) {
162         if (u[i] == n + 1) {
163             g.addArc(u[i], v[i], c[i], 0);
164         } else {
165             g.addArc(u[i], v[i], c[i], -(a[i] + mid) + d[i]);
166             g.addArc(u[i], v[i], inf, b[i] + mid + d[i]);
167 //            cost += c[i] * (-d[i] + a[i] + mid);
168             cost += c[i] * (-d[i] + a[i] + mid);
169         }
170     }
171     cost += network.min_cost();
172     return  cost < 0;
173 }
174 
175 inline void solve() {
176     double l = 0, r = init_ans, mid;
177     for (int t = 0; t < 128 && l < r - eps; t++) {
178         mid = (l + r) / 2;
179         if (check(mid))
180             l = mid;
181         else
182             r = mid;
183     }
184     printf("%.2lf\n", l);
185 }
186 
187 int main() {
188     init();
189     solve();
190     return 0;
191 }