uva 11082 Matrix Decompressing
题目大意:给出一个矩阵前i列所有元素的和,和前j行所有元素的和,求这个矩阵解压以后的原型。(答案不唯一)
解题思路:先根据题目所给出的条件,求出每行每列的和。然后把每行每列都当成一个节点,设置一个超级源点连向所有行结点,容量为“该行的和减去列数”,设置一个超级汇点,使所有的列结点连向超级汇点,容量为“该列的和减去行数”,然后所有的行结点和列结点相连,容量为19。图建好了,之后求完最大流,行结点列结点对应边上的流量,就是解压后的矩阵的元素。
那么这里有一个问题,为什么上面的容量要设置成“该列的和减去行数”和“该行的和减去列数”还有“19”,是不是都少了什么?在建图之前,把矩阵中的每一个元素都减去1,所以每列减去了行数,每行减去列数。这样做的目的是为了保证最终矩阵中的每一个元素都在1~20之内。如果不作处理的话,会出现0流,不符合题目条件。所以在一开始全部减去一,流不会为负,最后输出的时候在全部都加上一,就符合了题目的条件。
>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <cstdlib>
#include <queue>
using namespace std;
typedef long long ll;
const int N = 255;
const int OF = 50;
const int FIN = 205;
const int INF = 0x3f3f3f3f;
int R, C, s, t;
int X[N], Y[N], A[N], B[N];
struct Edge{
int from, to, cap, flow;
};
vector<Edge> edges;
vector<int> G[FIN * 2];
void init() {
for (int i = 0; i < FIN * 2; i++) G[i].clear();
edges.clear();
}
void addEdge(int from, int to, int cap, int flow) {
edges.push_back((Edge){from, to, cap, 0});
edges.push_back((Edge){to, from, 0, 0});
int m = edges.size();
G[from].push_back(m - 2);
G[to].push_back(m - 1);
}
void input() {
for (int i = 0; i < R; i++) {
scanf("%d", &A[i]);
}
for (int i = 0; i < C; i++) {
scanf("%d", &B[i]);
}
X[0] = A[0] - C;
for (int i = 1; i < R; i++) {
X[i] = A[i] - A[i - 1] - C;
}
Y[0] = B[0] - R;
for (int i = 1; i < C; i++) {
Y[i] = B[i] - B[i - 1] - R;
}
for (int i = 1; i <= R; i++) {
addEdge(s, i, X[i - 1], 0);
}
for (int i = 1; i <= C; i++) {
addEdge(i + OF, t, Y[i - 1], 0);
}
for (int i = 1; i <= R; i++) {
for (int j = 1; j <= C; j++) {
addEdge(i, j + OF, 19, 0);
}
}
}
int vis[N], d[N];
int BFS() {
memset(vis, 0, sizeof(vis));
queue<int> Q;
Q.push(s);
d[s] = 0;
vis[s] = 1;
while (!Q.empty()) {
int u = Q.front(); Q.pop();
for (int i = 0; i < G[u].size(); i++) {
Edge &e = edges[G[u][i]];
if (!vis[e.to] && e.cap > e.flow) {
vis[e.to] = 1;
d[e.to] = d[u] + 1;
Q.push(e.to);
}
}
}
return vis[t];
}
int cur[N];
int DFS(int u, int a) {
if (u == t || a == 0) return a;
int flow = 0, f;
for (int &i = cur[u]; i < G[u].size(); i++) {
Edge &e = edges[G[u][i]];
if (d[u] + 1 == d[e.to] && (f = DFS(e.to, min(a, e.cap - e.flow))) > 0) {
e.flow += f;
edges[G[u][i]^1].flow -= f;
flow += f;
a -= f;
if (a == 0) break;
}
}
return flow;
}
int MF() {
int ans = 0;
while (BFS()) {
memset(cur, 0, sizeof(cur));
ans += DFS(s, INF);
}
return ans;
}
int ans[N][N];
void output() {
int k = MF();
for (int i = 0; i < edges.size(); i += 2) {
Edge &e = edges[i];
if (e.to < OF) continue;
ans[e.from][e.to - (OF)] = e.flow;
}
for (int i = 1; i <= R; i++) {
for (int j = 1; j <= C; j++) {
printf("%d ", ans[i][j] + 1);
}
puts("");
}
}
int main() {
int T, Case = 1;
scanf("%d", &T);
while (T--) {
printf("Matrix %d\n", Case++);
scanf("%d %d", &R, &C);
s = 0, t = FIN;
init();
input();
output();
if (T) puts("");
}
return 0;
}