1. 程式人生 > >UVa 11082 - Matrix Decompressing(最大流)

UVa 11082 - Matrix Decompressing(最大流)

增加 new cst 根據 ros 輸入 memset times mincut

鏈接:

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 }

UVa 11082 - Matrix Decompressing(最大流)