传送门:UVa 11082 Matrix Decompressing
题目大意:对于一个R行C列的正整数矩阵(1<=R,C<=20),设Ai和前i行所有元素之和,Bi为前i列所有元素之和。已知道R,C和数组A和B,找一个满足条件的矩阵。矩阵中的元素必须是1到20之间的正整数。输入保证有解。
题目分析:
设前 i 行元素之和为row[ i ],前 j 列元素之和为col[ j ],再设立超级源汇。那么当前行元素和就是row[ i ] - row[ i - 1 ],当前列元素和就是col[ j ] - col[ j - 1 ]。然后对于每一行增加对应的一个结点r,然后增加一条容量为当前行元素和d - C的边(s,r,d - C);对于每一列增加对应结点c,然后增加一条容量为当前列元素和d-R的边(c,t,d - R);同时对于每一对(r,c),增加一条容量为20-1的边。然后求(s,t)的最大流f。 这样每一条(r,c)边的流量+1即为符合要求的原矩阵中(r,c)点的元素值。
代码如下:
#include <stdio.h>
#include <string.h>
#include <algorithm>
#define clear(A, X) memset(A, X, sizeof A)
#define copy(A, B) memcpy(A, B, sizeof A)
using namespace std;
const int maxE = 1000000;
const int maxN = 100;
const int maxQ = 1000000;
const int maxM = 32;
const int oo = 0x3f3f3f3f;
struct Edge{
int v, n, c;
}edge[maxE];
int adj[maxN], cntE;
int Q[maxQ], head, tail;
int d[maxN], cur[maxN], pre[maxN], num[maxN];
int s, t, nv, N, M;
int matrix[maxM][maxM], row[maxM], col[maxM];
void addedge(int u, int v, int c){
edge[cntE].v = v; edge[cntE].c = c; edge[cntE].n = adj[u]; adj[u] = cntE++;
edge[cntE].v = u; edge[cntE].c = 0; edge[cntE].n = adj[v]; adj[v] = cntE++;
}
void rev_bfs(){
clear(num, 0);
clear(d, -1);
d[t] = 0;
num[0] = 1;
head = tail = 0;
Q[tail++] = t;
while(head != tail){
int u = Q[head++];
for(int i = adj[u]; ~i; i = edge[i].n){
int v = edge[i].v;
if(~d[v]) continue;
d[v] = d[u] + 1;
Q[tail++] = v;
num[d[v]]++;
}
}
}
int ISAP(){
copy(cur, adj);
rev_bfs();
int flow = 0, u = pre[s] = s, i;
while(d[s] < nv){
if(u == t){
int f = oo, neck;
for(i = s; i != t; i = edge[cur[i]].v){
if(f > edge[cur[i]].c){
f = edge[cur[i]].c;
neck = i;
}
}
for(i = s; i != t; i = edge[cur[i]].v){
edge[cur[i]].c -= f;
edge[cur[i] ^ 1].c += f;
}
flow += f;
u = neck;
}
for(i = cur[u]; ~i; i = edge[i].n) if(d[edge[i].v] + 1 == d[u] && edge[i].c) break;
if(~i){
cur[u] = i;
pre[edge[i].v] = u;
u = edge[i].v;
}
else{
if(0 == (--num[d[u]])) break;
int mind = nv;
for(i = adj[u]; ~i; i = edge[i].n){
if(edge[i].c && mind > d[edge[i].v]){
cur[u] = i;
mind = d[edge[i].v];
}
}
d[u] = mind + 1;
num[d[u]]++;
u = pre[u];
}
}
return flow;
}
void init(){
clear(adj, -1);
cntE = 0;
}
void work(){
init();
scanf("%d%d", &N, &M);
s = 0; t = N + M + 1; nv = t + 1;
row[0] = col[0] = 0;
for(int i = 1;i <= N; ++i){
scanf("%d", &row[i]);
addedge(s, i, row[i] - M - row[i - 1]);
}
for(int i = 1; i <= M; ++i){
scanf("%d", &col[i]);
addedge(i + N, t, col[i] - N - col[i - 1]);
}
for(int i = 1; i <= N; ++i) for(int j = 1; j <= M; ++j) addedge(i, j + N, 19);
ISAP();
for(int u = 1; u <= N; ++u) for(int i = adj[u]; ~i; i = edge[i].n){
if(edge[i].v != s) matrix[u][edge[i].v - N] = edge[i ^ 1].c + 1;
}
for(int i = 1; i <= N; ++i) for(int j = 1; j <= M; ++j) printf("%d%c", matrix[i][j], j < M ? ' ' : '\n');
}
int main(){
int cas, T;
for(scanf("%d", &T), cas = 1; cas <= T; ++cas){
printf("Matrix %d\n", cas);
work();
}
return 0;
}