1. 程式人生 > >UVa Live 5131 Chips Challenge - 費用流

UVa Live 5131 Chips Challenge - 費用流

題目傳送門

  傳送門

題目大意

  給定一個$n\times n$的網格,每個網格上要麼已經有1個零件,要麼不能放置零件,要麼可以放置零件,問最多可以放置多少個零件,並滿足下面條件:

  • 一個格子上至多有1個零件
  • 第$i$行和第$i$列上的零件總數相等
  • 每一行或者每一列上的零件總數不超過零件總數的$\frac{A}{B}$

  或者輸出無解。

  假如開始的情況已經滿足了條件2。

  • 如果在$(x_1, y_1)$填一個零件,那麼就要在$(y_1, y_2)$處填一個零件;
  • 如果在$(y_1, y_2)$填一個零件,那麼就要在$(y_2, y_3)$處填一個零件;
  • ......
  • 最終在$(y_k, x_1)$處填一個零件。

  每一次增廣過程都是一個環。

  為了滿足限制3,分別對行列建點,設第$i$行的點是$X_i$,第$i$列的點是$Y_i$。那麼列舉上界$limit$,那麼第一部分建圖大概是:

  • $Y_i$向$X_i$連一條邊,容量為第$i$行還可以填的零件的數量,費用為0
  • 當$(i, j)$可以放置零件的時候$X_i$向$Y_j$連一條邊,容量為1,費用為1

  當經過$(Y_i, X_i)$時意味著在這一行上填了某個數。經過$Y_i$是意味著在這一列上填數。

  如果已經滿足條件的話可以直接跑最大費用迴圈流,但是非常不友好的是初始可能一些行列不滿足限制2.

  比如行上的零件可能會多點。這個時候用一下上下界流的思想。在做最大費用迴圈流的時候,稍微加一點邊:

  • 如果第$i$行上的零件多點,那麼列上要多填一點,所以會有更多的數填在這一列,所以$Y_i$向$T$連邊,容量為差值費用為0。
  • 如果第$i$列上的零件多點,那麼$S$向$Y_i$連邊,容量為差值費用為0.

  這樣就過了。。

  然後提一下最大費用迴圈流怎麼做。

  首先硬點所有正邊都要選,這樣會使得流量不平衡。然後用上下界流的思想在殘量網路上建立源匯跑最大費用最大流(這一部分費用是負的,可以理解為退回勁量少的費用使得滿足條件)。

Code

  1 /**
  2
* UVa Live 3 * Problem#5131 4 * Accepted 5 * Time: 1845ms 6 */ 7 #include <iostream> 8 #include <cstdlib> 9 #include <cstdio> 10 #include <queue> 11 using namespace std; 12 typedef bool boolean; 13 14 template <typename T> 15 void pfill(T* pst, const T* ped, T val) { 16 for ( ; pst != ped; *(pst++) = val); 17 } 18 19 typedef class Edge { 20 public: 21 int ed, nx, r, c; 22 23 Edge(int ed = 0, int nx = 0, int r = 0, int c = 0) : ed(ed), nx(nx), r(r), c(c) { } 24 } Edge; 25 26 typedef class MapManager { 27 public: 28 int* h; 29 vector<Edge> es; 30 31 MapManager() { } 32 MapManager(int n) { 33 h = new int[(n + 1)]; 34 pfill(h, h + n + 1, -1); 35 } 36 ~MapManager() { 37 delete[] h; 38 es.clear(); 39 } 40 41 void addEdge(int u, int v, int r, int c) { 42 es.push_back(Edge(v, h[u], r, c)); 43 h[u] = (signed) es.size() - 1; 44 } 45 46 void addArc(int u, int v, int cap, int c) { 47 addEdge(u, v, cap, c); 48 addEdge(v, u, 0, -c); 49 // cerr << u << " " << v << " " << cap << " " << c << '\n'; 50 } 51 52 Edge& operator [] (int p) { 53 return es[p]; 54 } 55 } MapManager; 56 57 const signed int inf = (signed) (~0u >> 1); 58 59 typedef class Network { 60 public: 61 int S, T; 62 MapManager g; 63 64 int flow; 65 int *le; 66 int *f, *mf; 67 boolean *vis; 68 69 Network() { } 70 // be sure T is the last node 71 Network(int S, int T) : S(S), T(T), g(T + 1) { 72 f = new int[(T + 1)]; 73 le = new int[(T + 1)]; 74 mf = new int[(T + 1)]; 75 vis = new boolean[(T + 1)]; 76 pfill(vis, vis + T, false); 77 } 78 ~Network() { 79 delete[] f; 80 delete[] le; 81 delete[] mf; 82 delete[] vis; 83 } 84 85 int spfa() { 86 queue<int> que; 87 pfill(f, f + T + 1, -inf); 88 que.push(S); 89 f[S] = 0, le[S] = -1, mf[S] = inf; 90 while (!que.empty()) { 91 int e = que.front(); 92 que.pop(); 93 vis[e] = false; 94 for (int i = g.h[e], eu, w; ~i; i = g[i].nx) { 95 if (!g[i].r) 96 continue; 97 eu = g[i].ed, w = f[e] + g[i].c; 98 if (w > f[eu]) { 99 f[eu] = w, le[eu] = i, mf[eu] = min(mf[e], g[i].r); 100 if (!vis[eu]) { 101 vis[eu] = true; 102 que.push(eu); 103 } 104 } 105 } 106 } 107 if (f[T] == -inf) 108 return inf; 109 flow += mf[T]; 110 int rt = 0; 111 for (int p = T, e; ~le[p]; p = g[e ^ 1].ed) { 112 e = le[p]; 113 g[e].r -= mf[T]; 114 g[e ^ 1].r += mf[T]; 115 rt += mf[T] * g[e].c; 116 } 117 return rt; 118 } 119 120 int max_cost() { 121 flow = 0; 122 int rt = 0, delta; 123 while ((delta = spfa()) != inf) { 124 rt += delta; 125 // cerr << delta << '\n'; 126 } 127 return rt; 128 } 129 } Network; 130 131 typedef class CirculatingNetwork : public Network { 132 public: 133 int n; 134 int ans; 135 int *dif; 136 int full_flow; 137 138 CirculatingNetwork() { } 139 CirculatingNetwork(int n) : Network(n + 1, n + 2), n(n), ans(0), full_flow(0) { 140 dif = new int[(n + 1)]; 141 pfill(dif + 1, dif + n + 1, 0); 142 } 143 ~CirculatingNetwork() { 144 delete[] dif; 145 } 146 147 void addEdge(int u, int v, int c, int w) { 148 if (w <= 0) 149 g.addArc(u, v, c, w); 150 else { 151 ans += w; 152 full_flow += c; 153 dif[u] += w; 154 dif[v] -= w; 155 g.addArc(v, u, c, -w); 156 } 157 } 158 159 void addArc(int u, int v, int c, int w) { 160 g.addArc(u, v, c, w); 161 } 162 163 int cir_max_cost() { 164 for (int i = 1; i <= n; i++) { 165 if (dif[i] > 0) { 166 g.addArc(i, T, dif[i], 0); 167 } else if (dif[i] < 0) { 168 g.addArc(S, i, -dif[i], 0); 169 } 170 } 171 ans += max_cost(); 172 return (full_flow == flow) ? (ans) : (-1); 173 } 174 } CirculatingNetwork; 175 176 const int N = 45; 177 178 int n, A, B; 179 int Case; 180 char a[N][N]; 181 int num_row[N], num_col[N]; 182 183 inline boolean solve() { 184 scanf("%d%d%d", &n, &A, &B); 185 if (!n && !A && !B) 186 return false; 187 for (int i = 1; i <= n; i++) { 188 scanf("%s", a[i] + 1); 189 } 190 pfill(num_row + 1, num_row + n + 1, 0); 191 pfill(num_col + 1, num_col + n + 1, 0); 192 int low = 0, have = 0; 193 for (int i = 1; i <= n; i++) 194 for (int j = 1; j <= n; j++) 195 if (a[i][j] == 'C') { 196 low = max(low, ++num_row[i]); 197 low = max(low, ++num_col[j]); 198 have++; 199 } 200 int ans = -1; 201 for (int lim = low; lim <= n * n * A / B; lim++) { 202 CirculatingNetwork network(n << 1); 203 for (int i = 1; i <= n; i++) { 204 if (num_row[i] < num_col[i]) { 205 network.dif[i + n] -= num_col[i] - num_row[i]; 206 } else if (num_row[i] > num_col[i]) { 207 network.dif[i + n] += num_row[i] - num_col[i]; 208 } 209 network.addEdge(i + n, i, lim - num_row[i], 0); 210 } 211 for (int i = 1; i <= n; i++) { 212 for (int j = 1; j <= n; j++) { 213 if (a[i][j] == '.') { 214 network.addEdge(i, j + n, 1, 1); 215 } 216 } 217 } 218 int ret = network.cir_max_cost(); 219 if ((ret + have) * A / B >= lim) 220 ans = max(ans, ret); 221 // cerr << lim << " " << ret << '\n'; 222 } 223 printf("Case %d: ", ++Case); 224 if (ans == -1) 225 puts("impossible"); 226 else 227 printf("%d\n", ans); 228 return true; 229 } 230 231 int main() { 232 while (solve()); 233 return 0; 234 }