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 }

猜你喜欢

转载自www.cnblogs.com/yyf0309/p/10198057.html