UVa 11082 - Matrix Decompressing(最大流)
链接:
https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&page=show_problem&problem=2023
题意:
对于一个R行C列的正整数矩阵(1≤R,C≤20),设Ai为前i行所有元素之和,Bi为前i列所有元素之和。
已知R,C和数组A和B,找一个满足条件的矩阵。矩阵中的元素必须是1~20之间的正整数。输入保证有解。
分析:
首先根据Ai和Bi计算出第i行的元素之和Ai'和第i列的元素之和Bi'。
如果把矩阵里的每个数都减1,则每个Ai'会减少C,而每个Bi'会减少R。
这样一来,每个元素的范围变成了0~19,它的好处很快就能看到。
建立一个二分图,每行对应一个X结点,每列对应一个Y结点,然后增加源点s和汇点t。
对于每个结点Xi,从s到Xi连一条弧,容量为Ai'-C;从Yi到t连一条弧,容量为Bi'-R。
而对于每对结点(Xi,Yj),从Xi向Yj连一条弧,容量为19。
接下来求s-t的最大流,如果所有s出发和到达t的边都满载,说明问题有解,
结点Xi->Yj的流量就是格子(i,j)减1之后的值。
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <queue> 4 #include <vector> 5 using namespace std; 6 7 /// 结点下标从0开始,注意maxn 8 struct Dinic { 9 static const int maxn = 50 + 5; 10 static const int INF = 0x3f3f3f3f; 11 struct Edge { 12 int from, to, cap, flow; 13 }; 14 15 int n, m, s, t; // 结点数,边数(包括反向弧),源点编号和汇点编号 16 vector<Edge> edges; // 边表。edges[e]和edges[e^1]互为反向弧 17 vector<int> G[maxn]; // 邻接表,G[i][j]表示结点i的第j条边在e数组中的序号 18 bool vis[maxn]; // BFS使用 19 int d[maxn]; // 从起点到i的距离 20 int cur[maxn]; // 当前弧下标 21 22 void init(int n) { 23 this->n = n; 24 edges.clear(); 25 for(int i = 0; i < n; i++) G[i].clear(); 26 } 27 void AddEdge(int from, int to, int cap) { 28 edges.push_back((Edge){from, to, cap, 0}); 29 edges.push_back((Edge){to, from, 0, 0}); 30 m = edges.size(); 31 G[from].push_back(m-2); 32 G[to].push_back(m-1); 33 } 34 bool BFS() { 35 memset(vis, 0, sizeof(vis)); 36 queue<int> Q; 37 Q.push(s); 38 vis[s] = 1; 39 d[s] = 0; 40 while(!Q.empty()) { 41 int x = Q.front(); Q.pop(); 42 for(int i = 0; i < G[x].size(); i++) { 43 Edge& e = edges[G[x][i]]; 44 if(!vis[e.to] && e.cap > e.flow) { // 只考虑残量网络中的弧 45 vis[e.to] = 1; 46 d[e.to] = d[x] + 1; 47 Q.push(e.to); 48 } 49 } 50 } 51 return vis[t]; 52 } 53 int DFS(int x, int a) { 54 if(x == t || a == 0) return a; 55 int flow = 0, f; 56 for(int& i = cur[x]; i < G[x].size(); i++) { // 从上次考虑的弧 57 Edge& e = edges[G[x][i]]; 58 if(d[x]+1 == d[e.to] && (f=DFS(e.to, min(a, e.cap-e.flow))) > 0) { 59 e.flow += f; 60 edges[G[x][i]^1].flow -= f; 61 flow += f; 62 a -= f; 63 if(a == 0) break; 64 } 65 } 66 return flow; 67 } 68 int Maxflow(int s, int t) { 69 this->s = s; this->t = t; 70 int flow = 0; 71 while(BFS()) { 72 memset(cur, 0, sizeof(cur)); 73 flow += DFS(s, INF); 74 } 75 return flow; 76 } 77 vector<int> Mincut() { // 在Maxflow之后调用 78 vector<int> ans; 79 for(int i = 0; i < edges.size(); i++) { 80 Edge& e = edges[i]; 81 if(vis[e.from] && !vis[e.to] && e.cap > 0) ans.push_back(i); 82 } 83 return ans; 84 } 85 }; 86 87 const int UP = 20 + 5; 88 int id[UP][UP]; 89 Dinic dc; 90 91 int main() { 92 int T, R, C; 93 scanf("%d", &T); 94 for(int cases = 1; cases <= T; cases++) { 95 scanf("%d%d", &R, &C); 96 dc.init(R+C+2); 97 int start = R+C, finish = R+C+1, last = 0; 98 for(int v, i = 0; i < R; i++) { 99 scanf("%d", &v); 100 dc.AddEdge(start, i, v - last - C); 101 last = v; 102 } 103 last = 0; 104 for(int v, i = 0; i < C; i++) { 105 scanf("%d", &v); 106 dc.AddEdge(R+i, finish, v - last - R); 107 last = v; 108 } 109 for(int r = 0; r < R; r++) { 110 for(int c = 0; c < C; c++) { 111 dc.AddEdge(r, R+c, 19); 112 id[r][c] = dc.edges.size() - 2; 113 } 114 } 115 116 dc.Maxflow(start, finish); 117 printf("Matrix %d\n", cases); 118 for(int r = 0; r < R; r++) { 119 for(int c = 0; c < C; c++) { 120 printf("%d ", dc.edges[id[r][c]].flow + 1); 121 } 122 printf("\n"); 123 } 124 printf("\n"); 125 } 126 return 0; 127 }