【有源汇有上下界可行流】POJ-2396(ZOJ-1994) Budget

34 篇文章 0 订阅
30 篇文章 0 订阅
Budget
Time Limit: 3000MS Memory Limit: 64M
    Special Judge

Description

We are supposed to make a budget proposal for this multi-site competition. The budget proposal is a matrix where the rows represent different kinds of expenses and the columns represent different sites. We had a meeting about this, some time ago where we discussed the sums over different kinds of expenses and sums over different sites. There was also some talk about special constraints: someone mentioned that Computer Center would need at least 2000K Rials for food and someone from Sharif Authorities argued they wouldn't use more than 30000K Rials for T-shirts. Anyway, we are sure there was more; we will go and try to find some notes from that meeting. 

And, by the way, no one really reads budget proposals anyway, so we'll just have to make sure that it sums up properly and meets all constraints.

Input

The first line of the input contains an integer N, giving the number of test cases. The next line is empty, then, test cases follow: The first line of each test case contains two integers, m and n, giving the number of rows and columns (m <= 200, n <= 20). The second line contains m integers, giving the row sums of the matrix. The third line contains n integers, giving the column sums of the matrix. The fourth line contains an integer c (c < 1000) giving the number of constraints. The next c lines contain the constraints. There is an empty line after each test case. 

Each constraint consists of two integers r and q, specifying some entry (or entries) in the matrix (the upper left corner is 1 1 and 0 is interpreted as "ALL", i.e. 4 0 means all entries on the fourth row and 0 0 means the entire matrix), one element from the set {<, =, >} and one integer v, with the obvious interpretation. For instance, the constraint 1 2 > 5 means that the cell in the 1st row and 2nd column must have an entry strictly greater than 5, and the constraint 4 0 = 3 means that all elements in the fourth row should be equal to 3.

Output

For each case output a matrix of non-negative integers meeting the above constraints or the string "IMPOSSIBLE" if no legal solution exists. Put  one empty line between matrices.

Sample Input

2

2 3 
8 10 
5 6 7 
4 
0 2 > 2 
2 1 = 3 
2 3 > 2 
2 3 < 5 

2 2 
4 5 
6 7 
1 
1 1 > 10

Sample Output

2 3 3 
3 3 4 

IMPOSSIBLE 
————————————————————忐忑的分割线————————————————————
前言:POJ上数据非常水,过了之后交到ZOJ上WA,调试了一下午 发现竟然是因为u == 0 && v == 0的情况枚举的时候少写了一个等于号……
思路:建图的时候要注意一下。
显然各行各列分别是顶点。从行流向列的话,没有上界的边上界是INF,那么怎么约束流量呢?各行之和的总和就是源点。源点需要向每一行连接一条边,容量恰好是各行之和。列同理。流向汇点。
这时候需要转换成无源汇的图。直接无视源点和汇点即可。它们的作用仅仅是提供流入的下界和或者流出的下界和。
之后建立超级源点和超级汇点,建立伴随网络,建图方法依旧是:原图拆边为上下界之差、流入该点下界和 - 流出该点下界和。
P.S. 传统的方法不是无视,而是另外添加一条从原始汇点向原始源点之间的边,值为INF,这样就可以保证原始源点、原始汇点和其它的点一样符合流量平衡条件。我这种方法没有丢弃任何约束条件,因此也正确。
代码如下:
/*
ID: j.sure.1
PROG:
LANG: C++
*/
/****************************************/
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <algorithm>
#include <cmath>
#include <stack>
#include <queue>
#include <vector>
#include <map>
#include <string>
#include <climits>
#include <iostream>
#define LL long long
using namespace std;
const int INF = 0x3f3f3f3f;
/****************************************/
const int R = 222, C = 22, N = 333, M = 44444;
int tot, S, T, head[N], cur[N], lev[N], q[N], s[N];
struct Node {
	int u, v, w;
	int next;
}edge[M];
int r, c, sum_r[R], sum_c[C], b[R][C], h[R][C];

void init()
{
	tot = 0; memset(head, -1, sizeof(head));
}

void add(int u, int v, int w)
{
	edge[tot].u = u; edge[tot].v = v; edge[tot].w = w;
	edge[tot].next = head[u]; head[u] = tot++;
}

bool bfs()
{
	memset(lev, -1, sizeof(lev));
	int fron = 0, rear = 0;
	lev[S] = 0;
	q[rear++] = S;
	while(fron < rear) {
		int u = q[fron%N]; fron++;
		for(int i = head[u]; ~i; i = edge[i].next) {
			int v = edge[i].v;
			if(edge[i].w && lev[v] == -1) {
				lev[v] = lev[u] + 1;
				q[rear%N] = v; rear++;
				if(v == T) return true;
			}
		}
	}
	return false;
}

void Dinic()
{
	while(bfs()) {
		memcpy(cur, head, sizeof(head));
		int u = S, top = 0;
		while(1) {
			if(u == T) {
				int mini = INF, loc;
				for(int i = 0; i < top; i++) {
					if(mini > edge[s[i]].w) {
						mini = edge[s[i]].w;
						loc = i;
					}
				}
				for(int i = 0; i < top; i++) {
					edge[s[i]].w -= mini;
					edge[s[i]^1].w += mini;
				}
				top = loc;
				u = edge[s[top]].u;
			}
			int &i = cur[u];
			for(; ~i; i = edge[i].next) {
				int v = edge[i].v;
				if(edge[i].w && lev[v] == lev[u] + 1) break;
			}
			if(~i) {
				s[top++] = i;
				u = edge[i].v;
			}
			else {
				if(!top) break;
				lev[u] = -1;
				u = edge[s[--top]].u;
			}
		}
	}
}

void getlim(int u, int v, char op, int w)
{
	switch(op)
	{
		case '=': b[u][v] = h[u][v] = w; break;
		case '<': h[u][v] = min(h[u][v], w - 1); break;
		case '>': b[u][v] = max(b[u][v], w + 1); break;
	}
}

void build()
{
	S = 0; T = r+c+1;
	for(int i = 1; i <= r; i++) {
		for(int j = 1; j <= c; j++) {
			add(i, j+r, h[i][j] - b[i][j]);
			add(j+r, i, 0);
		}
	}
	for(int i = 1; i <= r+c; i++) {
		int f = i <= r ? sum_r[i] : -sum_c[i-r];
		if(i <= r) for(int j = 1; j <= c; j++) {
			f -= b[i][j];
		}
		else for(int j = 1; j <= r; j++) {
			f += b[j][i-r];
		}
		if(f > 0) {
			add(S, i, f); add(i, S, 0);
		}
		else if(f < 0) {
			add(i, T, -f); add(T, i, 0);
		}
	}
}

bool judge()
{
	for(int i = head[S]; ~i; i = edge[i].next) {
		if(edge[i].w) return false;
	}//检查可行流
	for(int i = 0; i < r*c; i++) {
		int x = edge[i<<1].u, y = edge[i<<1].v;
		printf("%d", edge[i<<1|1].w + b[x][y-r]);
		if(i != c-1 && i != r*c-1) printf(" ");
		else puts("");
	}
	return true;
}

int main()
{
#ifdef J_Sure
//	freopen("000.in", "r", stdin);
//	freopen(".out", "w", stdout);
#endif
	int TT; bool kase = 0;
	scanf("%d", &TT);
	while(TT--) {
		int m, u, v, w;
		char op;
		scanf("%d%d", &r, &c);
		for(int i = 1; i <= r; i++) {
			scanf("%d", &sum_r[i]);
		}
		for(int i = 1; i <= c; i++) {
			scanf("%d", &sum_c[i]);
		}
		for(int i = 1; i <= r; i++) {
			for(int j = 1; j <= c; j++) {
				b[i][j] = 0; h[i][j] = INF;
			}
		}
		scanf("%d", &m);
		while(m--) {
			scanf("%d%d %c%d", &u, &v, &op, &w);
			if(!u && !v) {
				for(int i = 1; i <= r; i++) {
					for(int j = 1; j <= c; j++) {
						getlim(i, j, op, w);
					}
				}
			}
			else if(!u) {
				for(int i = 1; i <= r; i++) {
					getlim(i, v, op, w);
				}
			}
			else if(!v) {
				for(int j = 1; j <= c; j++) {
					getlim(u, j, op, w);
				}
			}
			else getlim(u, v, op, w);
		}
		init();
		build();
		Dinic();
		if(kase) puts("");
		kase = 1;
		if(!judge()) puts("IMPOSSIBLE");
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值