POJ 2396 Budget(有上下限的最大流)

本文深入探讨了上下限最大流算法在解决特定类型问题中的应用,如在矩阵元素受限制的情况下寻找可行解。通过详细解释算法流程和实现细节,为读者提供了理解和实践该算法的全面指南。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

题目链接:http://poj.org/problem?id=2396

题意:输入的第一行是测试数据的个数。每组测试数据的第一行是N和M。第二行是N个数,表示N行的和,第三行是M个数,表示M列的和。接下来一个K,表示有以下K个限制,每个限制的形式X Y Z W,其中Z是< > 或者=,表示第X行第Y列的元素和W的大小关系。假如Z是>,那么说明第X行第Y列的元素必须大于W。如果X是0,意思指所有第Y列的数和W的大小关系;如果Y是0,意思指所有第X行的数和W的大小关系;如果X和Y均为0,则表示整个矩阵和W的大小关系。如果有满足所有条件的矩阵,输出;没有的话,输出IMPOSSIBLE。

思路:上下限最大流。

#include <stdio.h>
#include <string.h>
#include <queue>
#define MAX 230
#define min(x,y) ((x)<(y)?(x):(y))
#define max(x,y) ((x)>(y)?(x):(y))
using namespace std;

const int INF=1000000000;
int high[MAX][MAX],low[MAX][MAX];
int cap[MAX][MAX];
int in[MAX],out[MAX],inc[MAX],pre[MAX],visit[MAX];
int n,m,s,t,ss,tt,sum;


int r[MAX],c[MAX];


void InPut()
{
	int i,j,num,u,v,w;
    char ch;

	memset(high,0,sizeof(high));
	memset(low,0,sizeof(low));
	scanf("%d%d",&n,&m);
	for(i=1;i<=n;i++) scanf("%d",&r[i]);
    for(i=1;i<=m;i++) scanf("%d",&c[i]);
	for(i=1;i<=n;i++)for(j=1;j<=m;j++) high[i][j+n]=INF;
	for(scanf("%d",&num);num--;)
	{
		scanf("%d%d %c%d",&u,&v,&ch,&w);
		if(u==0&&v!=0)
		{
			if(ch=='=')for(i=1;i<=n;i++)low[i][v+n]=high[i][v+n]=w;
			else if(ch=='<')for(i=1;i<=n;i++)high[i][v+n]=min(high[i][v+n],w-1);
			else for(i=1;i<=n;i++)low[i][v+n]=max(low[i][v+n],w+1);
		}
		else if(u!=0&&v==0)
		{
			if(ch=='=')for(i=1;i<=m;i++)low[u][i+n]=high[u][i+n]=w;
			else if(ch=='<')for(i=1;i<=m;i++)high[u][i+n]=min(high[u][i+n],w-1);
			else for(i=1;i<=m;i++)low[u][i+n]=max(low[u][i+n],w+1);
		}
		else if(u==0&&v==0)
		{
			for(i=1;i<=n;i++)for(j=1;j<=m;j++)
			{
				if(ch=='=')	low[i][j+n]=high[i][j+n]=w;
				else if(ch=='<')high[i][j+n]=min(high[i][j+n],w-1);
				else low[i][j+n]=max(low[i][j+n],w+1);
			}
		}
		else
		{
			if(ch=='=')low[u][v+n]=high[u][v+n]=w;
			else if(ch=='<')high[u][v+n]=min(high[u][v+n],w-1);
			else low[u][v+n]=max(low[u][v+n],w+1);
		}
	}
	s=0;t=n+m+1;
	for(i=1;i<=n;i++)low[s][i]=high[s][i]=r[i];
	for(i=1;i<=m;i++)low[i+n][t]=high[i+n][t]=c[i];
}



int BFS(int s,int t)
{
	int i,u;
	queue<int> Q;

	memset(pre,-1,sizeof(pre));
	memset(visit,0,sizeof(visit));
	Q.push(s);visit[s]=1;inc[s]=INF;
	while(!Q.empty())
	{
		u=Q.front();
		Q.pop();

		for(i=0;i<=t;i++) if(!visit[i]&&cap[u][i])
		{
			inc[i]=min(inc[u],cap[u][i]);
			pre[i]=u;
			visit[i]=1;
			if(i==t) return 1;
			Q.push(i);
		}
	}
	return 0;
}

int Maxflow(int s,int t)
{
	int maxflow=0,i;

	memset(inc,0,sizeof(inc));
	while(BFS(s,t))
	{
		maxflow+=inc[t];
		for(i=t;i!=s;i=pre[i])
		{
			cap[pre[i]][i]-=inc[t];
			cap[i][pre[i]]+=inc[t];
		}
	}
	return maxflow;
}

int limitMaxflow()
{
	int i,j,ans;

	memset(in,0,sizeof(in));
	memset(out,0,sizeof(out));
	memset(cap,0,sizeof(cap));
	for(sum=0,i=0;i<=t;i++) for(j=0;j<=t;j++)
	{
		cap[i][j]=high[i][j]-low[i][j];
		out[i]+=low[i][j];
		in[j]+=low[i][j];
		sum+=low[i][j];
	}
	for(ss=t+1,tt=t+2,i=0;i<=t;i++) cap[ss][i]=in[i],cap[i][tt]=out[i];
	cap[t][s]=INF;
    ans=Maxflow(ss,tt);
    if(ans!=sum)  return 0;
	cap[t][s]=cap[s][t]=0;
    ans=Maxflow(s,t);
	return 1;
}


int C;

int main()
{
	for(scanf("%d",&C);C--;)
    {
        InPut();
        if(!limitMaxflow())
        {
            puts("IMPOSSIBLE");
            continue;
        }
        int i,j;
        for(i=1;i<=n;i++)
		{
			for(j=1;j<=m;j++) printf("%d ",cap[j+n][i]+low[i][j+n]);
            printf("\n");
		}
    }
	return 0;
}

  

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值