【最大流】HDU 4888 Redraw Beautiful Drawings
题意:n*m的矩阵,每个格子可以是0~k,给出各行的和和各列的和,求格子数字唯一方案,或判断无解或不唯一
思路:最大流,每行一个点,每列一个点,起点到每行的点连流量等于这行的和的边,每列的点连流量等于这列的和的边到终点,每行的点连到每列的点流量为K的点。所有行的和不等于所有列的和 或 最大流不等于所有行的和 则无解。有解的话再判有没有环,有环说明多解,判环新技能--
代码:
1 #include <cstdio> 2 #include <cstring> 3 #include <vector> 4 #include <queue> 5 #include <algorithm> 6 7 using namespace std; 8 9 const int MAX_N = 807; 10 const int MAX_E = MAX_N * MAX_N * 5; 11 const int INF = 0x3f3f3f3f; 12 13 struct Edge { 14 int v, nxt; 15 long long cap; 16 Edge() { 17 18 } 19 Edge(int _v, int _nxt, long long _cap) { 20 v = _v, nxt = _nxt, cap = _cap; 21 } 22 }; 23 24 Edge G[MAX_E]; 25 int edgecnt, head[MAX_N]; 26 int gap[MAX_N], d[MAX_N]; 27 28 struct Isap { 29 int n, s, t; 30 void init(int n, int s, int t) { 31 this->n = n, this->s = s, this->t = t; 32 edgecnt = 0; 33 memset(head, -1, sizeof head); 34 } 35 void addedge(int u, int v, long long cap) { 36 G[edgecnt] = Edge(v, head[u], cap); 37 head[u] = edgecnt++; 38 G[edgecnt] = Edge(u, head[v], 0); 39 head[v] = edgecnt++; 40 } 41 long long dfs(int u, long long tot) { 42 if (u == t) return tot; 43 int minh = n - 1; 44 long long leave = tot; 45 for (int i = head[u]; ~i && leave; i = G[i].nxt) { 46 int v = G[i].v; 47 if (G[i].cap > 0) { 48 if (d[v] + 1 == d[u]) { 49 long long c = dfs(v, min(leave, G[i].cap)); 50 G[i].cap -= c; 51 G[i ^ 1].cap += c; 52 leave -= c; 53 if (d[s] >= n) 54 return tot - leave; 55 } 56 minh = min(minh, d[v]); 57 } 58 } 59 if (leave == tot) { 60 --gap[d[u]]; 61 if (gap[d[u]] == 0) d[s] = n; 62 d[u] = minh + 1; 63 ++gap[d[u]]; 64 } 65 return tot - leave; 66 } 67 long long maxFlow() { 68 long long ret = 0; 69 memset(gap, 0, sizeof gap); 70 memset(d, 0, sizeof d); 71 gap[0] = n; 72 while (d[s] < n) { 73 ret += dfs(s, INF); 74 } 75 return ret; 76 } 77 }; 78 79 int n, m, k; 80 int mat[MAX_N][MAX_N]; 81 int c[MAX_N][MAX_N]; // 当前行时,前面是否有在i列可增j列可减的状态 82 83 int main() { 84 while (3 == scanf("%d %d %d", &n, &m, &k)) { 85 Isap ans; 86 ans.init(n + m + 2, 0, n + m + 1); 87 int s = 0, t = n + m + 1; 88 long long sum1 = 0, sum2 = 0; 89 for (int i = 1; i <= n; ++i) { 90 for (int j = 1; j <= m; ++j) { 91 ans.addedge(i, n + j, k); 92 } 93 } 94 for (int i = 1; i <= n; ++i) { 95 int rowSum = 0; 96 scanf("%d", &rowSum); 97 sum1 += rowSum; 98 ans.addedge(0, i, rowSum); 99 } 100 for (int i = 1; i <= m; ++i) { 101 int colSum = 0; 102 scanf("%d", &colSum); 103 sum2 += colSum; 104 ans.addedge(n + i, t, colSum); 105 } 106 int q = ans.maxFlow(); 107 if (sum1 != sum2 || q != sum1) puts("Impossible"); 108 else { 109 int edge = 0; 110 for (int i = 1; i <= n; ++i) { 111 for (int j = 1; j <= m; ++j, edge += 2) { 112 mat[i][j] = G[edge ^ 1].cap; 113 } 114 } 115 memset(c, false, sizeof c); 116 bool f = false; 117 for (int i = 1; i <= n; ++i) { 118 for (int j = 1; j <= m; ++j) { 119 for (int l = j + 1; l <= m; ++l) { 120 bool f1 = false, f2 = false; 121 if (mat[i][j] != k && mat[i][l] != 0) {// column j could add, column l could dec 122 if (c[l][j]) { 123 l = m + 1, j = m + 1, i = n + 1; 124 f = true; 125 } 126 f1 = true; 127 } 128 if (mat[i][j] != 0 && mat[i][l] != k) {// column l could add, column j could dec 129 if (c[j][l]) { 130 l = m + 1, j = m + 1, i = n + 1; 131 f = true; 132 } 133 f2 = true; 134 } 135 if (f1) c[j][l] = true; 136 if (f2) c[l][j] = true; 137 } 138 } 139 } 140 if (f) puts("Not Unique"); 141 else { 142 puts("Unique"); 143 for (int i = 1; i <= n; ++i) { 144 for (int j = 1; j <= m; ++j) { 145 if (j == 1) printf("%d", mat[i][j]); 146 else printf(" %d", mat[i][j]); 147 } 148 puts(""); 149 } 150 } 151 } 152 } 153 return 0; 154 }