poj2396

这道题目题意很简单,就是1-n 那个点表示n行,n+1-n+m+表示m列,然后行列相连,有个上下界,另设源点s=n+m+1到各行上下界为各行值,各列到汇点t=n+m+2上下界为列的和,然后上下界网络流即可。
#include<cstdio>
#include<cstring>
#define maxn 10000
#define inf 1<<30
int n,m,s,t,ss,tt,nn,head[300],gap[300],dis[300],T,cnt,le[300],min[300][300],max[300][300],sum,mp[300][30];
struct Edge
{
	int to,b,c,nxt;
} edge[maxn];
int MIN(int a,int b)
{
	return a<b?a:b;
}
int MAX(int a,int b)
{
	return a>b?a:b;
}
void clc()
{
	memset(head,-1,sizeof(head));
	memset(gap,0,sizeof(gap));
	memset(dis,0,sizeof(dis));
	memset(mp,0,sizeof(mp));
	for(int i=1;i<=250;i++)
	for(int j=1;j<=250;j++)
	{
		min[i][j]=0;
		max[i][j]=inf;
	}
	memset(le,0,sizeof(le));
}
void ad(int x,int y,int b,int c)
{
	edge[cnt].to=y;
	edge[cnt].b=b;
	edge[cnt].c=c;
	edge[cnt].nxt=head[x];
	head[x]=cnt++;
}
void add(int x,int y,int b,int c)
{
	ad(x,y,b,c);
	ad(y,x,0,0);
}
int build()
{
	ss=nn+1,tt=ss+1;
	for(int i=0;i<cnt;i++)
	{
		if(edge[i].c<edge[i].b)
			return 1;
		edge[i].c=edge[i].c-edge[i].b;
        le[edge[i].to]+=edge[i].b;
		le[edge[i^1].to]-=edge[i].b;
		edge[i].b+=edge[i].c;
	}
	for(int i=1;i<=nn;i++)
	{
		if(le[i]>0)
		add(ss,i,0,le[i]),sum+=le[i];
		else
		if(le[i]<0)
		add(i,tt,0,-le[i]);
	}
	return 0;
}
int dfs(int x,int flow)
{
    if(x==tt)
    return flow;
	int temp=flow;
	int pos=tt-1;
	int j;
	for(j=head[x];j!=-1;j=edge[j].nxt)
	{
		int y=edge[j].to;
		int c=edge[j].c;
		if(c>0&&dis[x]==dis[y]+1)
		{
			int temp_flow=dfs(y,MIN(c,temp));
			temp-=temp_flow;
			edge[j].c-=temp_flow;
			edge[j^1].c+=temp_flow;
			if(temp==0||dis[0]==tt)
			return flow-temp;
		}
		if(c>0&&pos>dis[y])
		pos=dis[y];
	}
	if(temp==flow)
	{
		if(!(--gap[dis[x]]))
		dis[0]=tt;
		else
		gap[dis[x]=pos+1]++;
	}
	return flow-temp;
}
int sap()	
{
	int maxflow=0;
	gap[0]==tt;
	while(dis[0]<tt)
	{
		maxflow+=dfs(ss,inf);
	}
	return sum==maxflow;
}
void print()
{
     for(int i=1;i<=n;i++)
     for(int j=head[i];j!=-1;j=edge[j].nxt)
     {
            int y=edge[j].to;
            if(y<=n+m)
            mp[i][y-n]=edge[j].b-edge[j].c;
     }
     for(int i=1;i<=n;i++)
     {
      for(int j=1;j<m;j++)
             printf("%d ",mp[i][j]);
             printf("%d\n",mp[i][m]);
     }      
}
int main()
{
	scanf("%d",&T);
	while(T--)
	{
		cnt=sum=0;
		scanf("%d%d",&n,&m);
		s=n+m+1,t=s+1,nn=t;
		clc();
		for(int i=1;i<=n;i++)
		{
			int tp;
			scanf("%d",&tp);
			add(s,i,tp,tp);
		}
		for(int i=1;i<=m;i++)
		{
			int tp;
			scanf("%d",&tp);
			add(i+n,t,tp,tp);
		}
		int qipa;
		scanf("%d",&qipa);
		for(int i=1;i<=qipa;i++)
		{
			int a,b,d,aa,bb;
			char c;
			scanf("%d%d %c%d",&a,&b,&c,&d);
			if(a==0)
			{
				a=1,aa=n;
			}
			else
			aa=a;
			if(b==0)
			{
				b=1,bb=m;
			}
			else
			bb=b;
			for(int i=a;i<=aa;i++)
			for(int j=b;j<=bb;j++)
			{
				if(c=='=')min[i][j]=MAX(min[i][j],d),max[i][j]=MIN(max[i][j],d);
				else
				if(c=='>')min[i][j]=MAX(min[i][j],d+1);
				else
				if(c=='<')max[i][j]=MIN(max[i][j],d-1);
			}
        }
		for(int i=1;i<=n;i++)
		for(int j=1;j<=m;j++)
		add(i,j+n,min[i][j],max[i][j]);
		add(t,s,0,inf); 
		if(build())
		{
			printf("IMPOSSIBLE\n");
			continue;
		}
		if(sap())
		print();
        else
        printf("IMPOSSIBLE\n");
	}
	return 0;
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值