Budget Poj 2396 含下界网络流

今天花了一天才A了一道题,不过回头上论坛一看发现大家都是做完后感慨良多,感觉也不虚此行。题目要求填充矩阵,且已知矩阵各行各列的和,以及对矩阵某些行某些列有相应的限制,求是否存在合理的填充,存在即输出。

由于各行各列的值已经知道,并且注意到矩阵横行和之和等于就矩阵竖行和之和,我们可以转化出一个流网络,节点是每一行和每一列,假想一个源节点在矩阵左边,汇节点在矩阵上方,则我们要做的就是让流从源经由矩阵留到汇,其中交叉点就是行和列的连边,从而转化为一个含上下界的流网络问题。

当然,由于我手上只有一个Dinic模板(对的,我还是忘了从哪里找来的,作者如果看见了请告诉我,立刻标出来源),而这个模板并不具有处理上下界的功能,所以我们要做进一步处理。对此http://blog.csdn.net/clove_unique/article/details/54884437一文中有很好的讲述,在此只引结论:

建图方法

将有上下界的网络流图转化成普通的网络流图

  • 首先建立附加源点ss和附加汇点tt
  • 对于原图中的边x->y,若限制为[b,c],那么连边x->y,流量为c-b
  • 对于原图中的某一个点i,记d(i)为流入这个点的所有边的下界和减去流出这个点的所有边的下界和 
    • 若d(i)>0,那么连边ss->i,流量为d(i)
    • 若d(i)<0,那么连边i->tt,流量为-d(i)

求解方法

在新图上跑ss到tt的最大流 
若新图满流,那么一定存在一种可行流 
此时,原图中每一条边的流量应为新图中对应的边的流量+这条边的流量下界

以此来转化为我的Dinic模板能解的形式进行。
#include <stdio.h>  
#include <algorithm>  
#include <iostream>  
using namespace std;
#include <queue>  
#define MAXN 300  
#define MAXE 10000 
#define maxm 203
#define maxn 23
#define INF 0x3f3f3f3f  

int mValue[maxm];
int nValue[maxn];
int d[maxm+maxn];
int upperValue[maxm][maxn];
int lowerValue[maxm][maxn];
bool isDetermined[maxm][maxn];
int m, n;
void init()
{
	memset(upperValue, 0x3f, sizeof(upperValue));
	memset(lowerValue, 0, sizeof(lowerValue));
	memset(mValue, 0, sizeof(int)*m);
	memset(nValue, 0, sizeof(int)*n);
	memset(isDetermined, 0, sizeof(isDetermined));
	memset(d, 0, sizeof(d));
}
void setBound(int i, int j, int w, char c)
{
	//printf("To set %d,%d with %d on %c\n", i, j, w, c);
	if (c == '<')
		upperValue[i][j] = min(upperValue[i][j], w-1);
	else if (c == '>')
		lowerValue[i][j] = max(lowerValue[i][j], w+1);
	else if (c == '=') {
		if (isDetermined[i][j] == false) {
			lowerValue[i][j] = w;
			upperValue[i][j] = w;
			isDetermined[i][j] = true;
		}
		else if (lowerValue[i][j] != w&&upperValue[i][j] != w)
			lowerValue[i][j] = upperValue[i][j] + 1;//manually cause exceptions
	}
}
void setBounds(int u, int v, int w,char c)
{
	int iStart, iEnd, jStart, jEnd;
	iStart = (u == 0) ? 0 : u - 1;
	iEnd = (u == 0) ? m - 1 : u - 1;
	jStart = (v == 0) ? 0 : v - 1;
	jEnd = (v == 0) ? n - 1 : v - 1;
	for (int i = iStart; i <= iEnd; i++)
		for (int j = jStart; j <= jEnd; j++)
			setBound(i, j, w, c);
}
void setBound()
{
	for (int i = 0; i < m; i++) {
		for (int j = 0; j < n; j++) {
			upperValue[i][j] = min(mValue[i], nValue[j]);
		}
	}
	int constraintNumber, u, v, w;
	char compare;
	scanf("%d", &constraintNumber);
	for (int i = 0; i < constraintNumber; i++) {
		scanf("%d %d %c %d", &u, &v, &compare, &w);
		setBounds(u, v, w, compare);
	}
}
bool simpleCheck()
{
	for (int i = 0; i < m; i++)
		for (int j = 0; j < n; j++)
			if (upperValue[i][j] < lowerValue[i][j])
				return false;
	return true;
}
class matchGraph
{
private:
	int s, t;
	int cnt;
	int Head[MAXN];//the number for the last edge of a certain vertex  
	int Next[MAXE];//pointing to the former edge of a certain edge?  
	int V[MAXE];//the vertex each edge points to  
	int W[MAXE];
	int Depth[MAXN];
	void _add(int u, int v, int w)
	{
		Next[cnt] = Head[u];//this mimics a list?  
		V[cnt] = v;
		W[cnt] = w;
		Head[u] = cnt;
		cnt++;
	}
	int _sourceNumber;
public:
	int order;
	void init(int oorder, int ss, int tt)
	{//s is the souce and t is the sink  
		this->order = oorder;
		s = ss;
		_sourceNumber = 0;
		t = tt;
		cnt = 0;
		memset(Head, -1, sizeof(Head));
		memset(Next, -1, sizeof(Next));
	}
	void addEdge(int u, int v, int w)
	{
		_add(u, v, w);
		_add(v, u, 0);
		if (u == s)
			_sourceNumber += w;
	}
	int dfs(int u, int dist)
	{//u being the present node and dist being the present flow  
		if (u == t)
			return dist;
		int i, di;
		for (i = Head[u]; i != -1; i = Next[i]) {
			if ((Depth[V[i]] == Depth[u] + 1) && W[i] != 0) {
				di = dfs(V[i], min(dist, W[i]));
				if (di > 0) {
					W[i] -= di;
					W[i ^ 1] += di;
					return di;
				}
			}
		}
		return 0;
	}
	bool bfs()
	{
		queue<int > Q;
		int u;
		while (!Q.empty())
			Q.pop();
		memset(Depth, 0, sizeof(Depth));
		Depth[s] = 1;
		Q.push(s);
		while (!Q.empty()) {
			u = Q.front();
			Q.pop();
			for (int i = Head[u]; i != -1; i = Next[i]) {
				if ((W[i] > 0) && Depth[V[i]] == 0) {
					Depth[V[i]] = Depth[u] + 1;
					Q.push(V[i]);
				}
			}
		}
		return Depth[t] > 0 ? true : false;
	}
	int Dinic()
	{
		int Ans = 0, dd;
		while (bfs()) 
			while (dd= dfs(s, INF)) 
				Ans += dd;
		if (Ans == _sourceNumber) 
			for (int i = 0; i < m; i++) 
				for (int j = 0; j < n; j++) 
					printf("%d%c", W[2 * (i*n + j) + 1] + lowerValue[i][j], j == n - 1 ? '\n' : ' ');
		else
			printf("IMPOSSIBLE\n");
		return Ans;
	}
};
int main()
{
	matchGraph mG;
	int k;
	scanf("%d", &k);//k is the number of testcases
	for(int l=0;l<k;l++) {
		scanf("%d %d", &m, &n);
		init();
		int size = m + n + 2;//2 for s and t before, 2 for ss and st
		mG.init(size, 0, size - 1);
		int temp, constraintNumber, row, column, weight;
		char c;
		for (int i = 0; i < m; i++) {
			scanf("%d", &mValue[i]);
			d[i] += mValue[i];//for getting the sum of lower bounds
		}
		for (int i = 0; i < n; i++) {
			scanf("%d", &nValue[i]);
			d[i + m] -= nValue[i];
		}
		setBound();
		if (!simpleCheck()) {
			printf("IMPOSSIBLE\n\n");
			continue;
		}
		for (int i = 0; i < m; i++) {
			for (int j = 0; j < n; j++) {
				mG.addEdge(i + 1, m + 1 + j, upperValue[i][j] - lowerValue[i][j]);
				d[i] -= lowerValue[i][j];
				d[m + j] += lowerValue[i][j];
			}
		}
		for (int i = 0; i < m+n; i++) {
			if (d[i] > 0)
				mG.addEdge(0, i + 1, d[i]);
			else if (d[i] < 0)
				mG.addEdge(i + 1, size - 1, -d[i]);
		}
		mG.Dinic();
		printf("\n");
	}
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值