UVa 11082 Matrix Decompressing 最大流

传送门: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;
}


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值