POJ 2396 Budget ——有上下界的网络流

给定矩阵的每行每列的和,和一些大于小于等于的限制。然后需要求出一组可行解。

上下界网络流。

大概的思想就是计算出每一个点他需要强行流入或者流出的量,然后建出超级源点和汇点,然后删除下界,就可以判断是否可行。

然后把新的上界作为限制,在原图中跑一边。

然后就是必须的+原图中的进行计算。

#include <queue>
#include <cstdio>
#include <cstring>
#include <iostream>
#include <algorithm>
using namespace std;
#define F(i,j,k) for (int i=j;i<=k;++i)
int up[205][205],down[205][205],tt,n,m,row[205];
#define inf 0x3f3f3f3f
#define maxn 50005
int ttt,clu[205],S=maxn-4,T=maxn-3,SS=maxn-2,TT=maxn-1;
int fr[maxn],h[maxn],to[maxn],ne[maxn],fl[maxn],en=0,ans,a[205][205];
int du[maxn],id[205][205],tot,Sum,s,t,ban[maxn],SSum,SSSum;

void add(int a,int b,int c)
{
	fr[en]=a;to[en]=b;ne[en]=h[a];fl[en]=c;h[a]=en++;
	fr[en]=b;to[en]=a;ne[en]=h[b];fl[en]=0;h[b]=en++;
}

int dis[maxn];
queue<int>q;

bool tell()
{
	memset(dis,-1,sizeof dis); dis[s]=0; q.push(s);
	while (!q.empty())
	{
		int x=q.front();q.pop();
		for (int i=h[x];i>=0;i=ne[i])
		if (dis[to[i]]==-1&&fl[i]>0&&!ban[i])
			dis[to[i]]=dis[x]+1,q.push(to[i]);
	}
	return dis[t]!=-1;
}

int zeng(int k,int now)
{
	int ret=0;
	if (k==t) return now;
	for (int i=h[k];i>=0&&now>ret;i=ne[i])
	if (dis[to[i]]==dis[k]+1&&fl[i]&&!ban[i]){
		int tmp=zeng(to[i],min(fl[i],now-ret));
		fl[i]-=tmp; fl[i^1]+=tmp; ret+=tmp;
	}
	if (!ret) dis[k]=-1;
	return ret;
}

int dinic(int S,int T)
{
	int ret=0,tmp=0;//printf("dinic %d %d
",S,T);
	s=S;t=T;
	while (tell()) while (tmp=zeng(s,inf)) ret+=tmp;
	return ret;
}

void build()
{
	en=0;memset(h,-1,sizeof h);memset(a,0,sizeof a);
	memset(du,0,sizeof du);
	memset(ban,0,sizeof ban);Sum=0;
	tot=0;
	F(i,1,n) F(j,1,m)
	{
		if (up[i][j]<down[i][j]) {ans=0;return;}
		du[i]-=down[i][j];
		du[j+n]+=down[i][j];
		up[i][j]-=down[i][j];
		a[i][j]+=down[i][j];
		add(i,j+n,up[i][j]);
	}
	F(i,1,n) add(S,i,row[i]);
	F(j,n+1,n+m) add(j,T,clu[j-n]);
	add(T,S,inf);
	F(i,1,n+m)
	{
		if (du[i]>0) add(SS,i,du[i]),Sum+=du[i];
		else if (du[i]<0) add(i,TT,-du[i]);
	}
	if (dinic(SS,TT)!=Sum) {ans=0;return;}
	else
	{
		ban[en-1]=1;ban[en-2]=1;
		for (int i=h[SS];i>=0;i=ne[i]) ban[i]=ban[i^1]=1;
		for (int i=h[TT];i>=0;i=ne[i]) ban[i]=ban[i^1]=1;
		if (dinic(S,T)!=SSum) {ans=0;return;}
		F(i,1,n)
		{
			for (int j=h[i];j>=0;j=ne[j])
				a[i][to[j]-n]+=fl[j^1];
		}
		ans=1; return;
	}
}

int main()
{
	scanf("%d",&tt);
	while (tt--)
	{
		memset(down,0,sizeof down);
		memset(up,0x3f,sizeof up);
		scanf("%d%d",&n,&m);SSum=SSSum=0;
		F(i,1,n) scanf("%d",&row[i]),SSum+=row[i];
		F(i,1,m) scanf("%d",&clu[i]),SSSum+=clu[i];
		scanf("%d",&ttt);
		F(i,1,ttt)
		{
			int x,y,z;char s[11];
			scanf("%d%d%s%d",&x,&y,s,&z);
			switch(s[0])
			{
				case '>':
					if (!x) F(i,1,n)
					{
						if (!y) F(j,1,m)
							down[i][j]=max(down[i][j],z+1);
						else
							down[i][y]=max(down[i][y],z+1);
					}
					else
					{
						if (!y) F(j,1,m)
							down[x][j]=max(down[x][j],z+1);
						else
							down[x][y]=max(down[x][y],z+1);
					}
				break;
				case '=':
					if (!x) F(i,1,n)
					{
						if (!y) F(j,1,m)
						{
							up[i][j]=min(up[i][j],z);
							down[i][j]=max(down[i][j],z);
						}
						else
						{
							up[i][y]=min(up[i][y],z);
							down[i][y]=max(down[i][y],z);
						}
					}
					else
					{
						if (!y) F(j,1,m)
						{
							up[x][j]=min(up[x][j],z);
							down[x][j]=max(down[x][j],z);
						}
						else
						{
							up[x][y]=min(up[x][y],z);
							down[x][y]=max(down[x][y],z);
						}
					}
				break;
				case '<':
					if (!x) F(i,1,n)
					{
						if (!y) F(j,1,m)
							up[i][j]=min(up[i][j],z-1);
						else
							up[i][y]=min(up[i][y],z-1);
					}
					else
					{
						if (!y) F(j,1,m)
							up[x][j]=min(up[x][j],z-1);
						else
							up[x][y]=min(up[x][y],z-1);
					}
				break;
			}
		}
		build();
		if ((!ans)||(SSum!=SSSum)) printf("IMPOSSIBLE
");
		else
		{
			F(i,1,n) F(j,1,m)
				printf("%d%c",a[i][j],j==m?'
':' ');
		}
		if (tt!=0)
		printf("
");
	}
}

  

原文地址:https://www.cnblogs.com/SfailSth/p/6647436.html