poj 2396 Budget 带上下界的网络流模型

#include<iostream>
#include<string>
#include<cmath>
#include<algorithm>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;

const int MAXN=255;
const int INF=1000000000;

int cap[MAXN][MAXN],flow[MAXN][MAXN],low[MAXN][MAXN],high[MAXN][MAXN];
//cap[][]网络中的容量,flow[][]流量分配,low[][],high[][]流量上下界
int r[MAXN],c[MAXN],q[MAXN],in[MAXN],out[MAXN],d[MAXN];
//in[u]:u所有入边的流量下界和,out[u]:u所有出边的流量下界和,fa[]:dinic中的层次
bool vist[MAXN];

void Init()
{
     memset(in,0,sizeof(in));
     memset(out,0,sizeof(out));
     memset(low,0,sizeof(low));
     memset(cap,0,sizeof(cap));
     memset(high,0,sizeof(high));
     memset(flow,0,sizeof(flow));
}

bool bfs(int s,int t,int n)//建立层次网络
{
	int i,tmp;
	memset(d,-1,sizeof(d));
	queue<int>Q;
	Q.push(s);
	d[s]=0;
	while(!Q.empty())
	{
		tmp=Q.front();
		Q.pop();
		for(i=0;i<n;i++)
			if(cap[tmp][i]>0&&d[i]==-1)
			{
				d[i]=d[tmp]+1;
				Q.push(i);
			}
	}
	if(d[t]!=-1)return true;
	else return false;
}

int dfs(int k,int t,int n,int sum)//扩展流量
{
	if(k==t)return sum;
	int i,os=sum;
	for(i=0;i<n;i++)
		if(d[i]==d[k]+1&&cap[k][i]>0)
		{
			int a=dfs(i,t,n,min(sum,cap[k][i]));
			cap[k][i]-=a;
			cap[i][k]+=a;
			flow[k][i]+=a;
			flow[i][k]-=a;
			sum-=a;
		}
		return os-sum;
}
int dinic(int s,int t,int n)
{
	int ans=0;
	while(bfs(s,t,n))
		ans+=dfs(s,t,n,INF);
	return ans;
}

void solve(int s,int t,int num,int n,int m)      //num为节点个数,n*m方阵
{
     int i,j,ss,tt,res,sum=0;
     ss=num;
     tt=num+1;
     for(i=0;i<num;i++)
      for(j=0;j<num;j++)
      {
          cap[i][j]=high[i][j]-low[i][j];        //该边容量为上下界流量之差
          out[i]+=low[i][j];                //统计点i所有出边的流量下界之和
          in[j]+=low[i][j];                   //统计点j所有入边的流量下界之和
          sum+=low[i][j];                     //所有边的流量下界之和
      }
     for(i=0;i<num;i++)                   //添加附加源点ss和汇点tt建立附加网络
     {
          cap[ss][i]=in[i];
          cap[i][tt]=out[i];
     }
     cap[t][s]=INF;                  //在附加网络中连边cap[t][s]=INF
     res=dinic(ss,tt,num+2);         //对附加网络求解最大流
     if(res!=sum)                     //附加网络的最大流不等于所有下界之和,则无解
     {
          printf("IMPOSSIBLE\n");
          return;
     }
     cap[t][s]=cap[s][t]=0;               //去掉边(t,s)和(s,t)
     res=dinic(s,t,num);                  //在对去边之后的图求解最大流
     for(i=1;i<=n;i++)                           //输出方阵
     {
         printf("%d",flow[i][1+n]+low[i][1+n]);
         for(j=2;j<=m;j++)
           printf(" %d",flow[i][j+n]+low[i][j+n]);
         printf("\n");
     }
}

int main()
{
    int i,j,s,t,u,v,w,m,n,num,ans,ncase;
    char ch;
    scanf("%d",&ncase);
    while(ncase--)
    {
         Init();
         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;
         scanf("%d",&ans);
         while(ans--)
         {
               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 if(ch=='>')
                     {
                          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 if(ch=='>')
                    {
                         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 if(ch=='>')
                              low[i][j+n]=max(low[i][j+n],w+1);
                     }
               }
               else if(u!=0&&v!=0)
               {
                    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 if(ch=='>')
                        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];
         solve(s,t,t+1,n,m);
         printf("\n");
    }
    return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值