Question link: http://acdream.info/problem? PID = 1, 1128
Problem descriptionwuyiqi falls into a maze consisting of n * m grids. A certain number of boxes are stacked on each grid. (I, j) indicates the grid of row I and column J. Wuyiqi can move a box on a grid to an adjacent grid or destroy it. That is, the boxes in (I, j) can be moved to (I-1, J), (I + 1, J), (I, J-1) and (I, j + 1 ), but cannot be moved out of the matrix range. Moving a box on the (I, j) grid to an adjacent grid consumes the RP value of X and destroying the RP value of Y. When the number of boxes in each row is equal and the number of boxes in each column is equal, wuyiqi can escape. Help wuyiqi calculate the minimum Rp value required for escape. Input
There are multiple groups of data.
The first row of each data group is two positive integers n and M (1 <= n, m <= 100 ).
The following two integers are X and Y (1 <= X, Y <= 100)
In the next n rows, each row has m non-negative integers. The number of J in row I is P (I, j) (0 <= P (I, j) <= 20) it indicates the number of boxes on the (I, j) grid. Output
Output The minimum Rp value required for wuyiqi escape.
Question: omitted.
Idea: Considering the results, the sum of each row is the same, and the sum of each column is the same. The sum of each row is a multiple of N, and the sum of each column is a multiple of M. Then the sum of the entire board must be a multiple of LCM (n, m.
Then enumerate the number of remaining boxes in the final board, and enumerate the multiples of LCM (n, m). If it is B, the number of boxes to be destroyed is (Sum-B) * y, sum indicates the total number of boxes.
Now we want to move the boxes between each row and set sumr [I] to the total number of boxes in row I. Now we need to change each row to B/n.
Create a Source Vertex, and the capacity of connecting one edge to each row is sumr [I], and the cost is 0. Create a sink, and each row is connected to one edge of the sink. The capacity is B/N and the cost is 0.
An edge is connected between adjacent rows. The capacity is positive infinity and the fee is X.
The minimum cost of running the largest stream can get the cost of moving the box between rows. Similarly, we can get the cost of moving boxes between columns.
Take the minimum value of the total price after enumeration.
PS: The spfa billing template that has been used in the past is incorrect when debugging is performed with the naked eye ......
Code (96 ms ):
1 #include <cstdio> 2 #include <iostream> 3 #include <algorithm> 4 #include <cstring> 5 #include <queue> 6 #include <numeric> 7 using namespace std; 8 typedef long long LL; 9 10 const int MAXN = 110; 11 const int MAXV = 110; 12 const int MAXE = 8 * MAXV; 13 const int INF = 0x7f7f7f7f; 14 15 struct SPFA_COST_FLOW { 16 int head[MAXV]; 17 int to[MAXE], next[MAXE], cost[MAXE], flow[MAXE]; 18 int n, ecnt, st, ed; 19 20 void init(int nn) { 21 n = nn; 22 memset(head + 1, -1, n * sizeof(int)); 23 ecnt = 0; 24 } 25 26 void add_edge(int u, int v, int c, int w) { 27 to[ecnt] = v; flow[ecnt] = c; cost[ecnt] = w; next[ecnt] = head[u]; head[u] = ecnt++; 28 to[ecnt] = u; flow[ecnt] = 0; cost[ecnt] = -w; next[ecnt] = head[v]; head[v] = ecnt++; 29 } 30 31 bool vis[MAXV]; 32 int dis[MAXV], pre[MAXV]; 33 queue<int> que; 34 35 bool spfa() { 36 memset(vis + 1, 0, n * sizeof(bool)); 37 memset(dis + 1, 0x7f, n * sizeof(int)); 38 dis[st] = 0; que.push(st); 39 while(!que.empty()) { 40 int u = que.front(); que.pop(); 41 vis[u] = false; 42 for(int p = head[u]; ~p; p = next[p]) { 43 int &v = to[p]; 44 if(flow[p] && dis[v] > dis[u] + cost[p]) { 45 dis[v] = dis[u] + cost[p]; 46 pre[v] = p; 47 if(!vis[v]) { 48 que.push(v); 49 vis[v] = true; 50 } 51 } 52 } 53 } 54 return dis[ed] < INF; 55 } 56 57 int maxFlow, minCost; 58 int min_cost_flow(int ss, int tt) { 59 st = ss, ed = tt; 60 maxFlow = minCost = 0; 61 while(spfa()) { 62 int u = ed, tmp = INF; 63 while(u != st) { 64 tmp = min(tmp, flow[pre[u]]); 65 u = to[pre[u] ^ 1]; 66 } 67 u = ed; 68 while(u != st) { 69 flow[pre[u]] -= tmp; 70 flow[pre[u] ^ 1] += tmp; 71 u = to[pre[u] ^ 1]; 72 } 73 maxFlow += tmp; 74 minCost += tmp * dis[ed]; 75 } 76 return minCost; 77 } 78 } G; 79 80 int mat[MAXN][MAXN]; 81 int sumr[MAXN], sumc[MAXN]; 82 int n, m, x, y; 83 84 int calc(int sum[], int n, int c) { 85 int ss = n + 1, tt = n + 2; 86 G.init(n + 2); 87 for(int i = 1; i <= n; ++i) 88 G.add_edge(ss, i, sum[i], 0), G.add_edge(i, tt, c, 0); 89 for(int i = 1; i < n; ++i) 90 G.add_edge(i, i + 1, INF, x), G.add_edge(i + 1, i, INF, x); 91 return G.min_cost_flow(ss, tt); 92 } 93 94 int solve() { 95 int sum = accumulate(sumr + 1, sumr + n + 1, 0), ans = sum * y; 96 int lcm = n * m / __gcd(n, m); 97 for(int b = lcm; b <= sum; b += lcm) { 98 ans = min(ans, (sum - b) * y + calc(sumr, n, b / n) + calc(sumc, m, b / m)); 99 }100 return ans;101 }102 103 int main() {104 while(scanf("%d%d", &n, &m) != EOF) {105 scanf("%d%d", &x, &y);106 for(int i = 1; i <= n; ++i)107 for(int j = 1; j <= m; ++j) scanf("%d", &mat[i][j]);108 memset(sumr + 1, 0, n * sizeof(int));109 memset(sumc + 1, 0, m * sizeof(int));110 for(int i = 1; i <= n; ++i) {111 for(int j = 1; j <= m; ++j) {112 sumr[i] += mat[i][j];113 sumc[j] += mat[i][j];114 }115 }116 printf("%d\n", solve());117 }118 }View code