POJ 2396 有源汇上下界最大流

15 篇文章 0 订阅
9 篇文章 0 订阅


最大流 二分图模型

X 集合为行, Y集合为列, 对每个数来说,bom[i][j]表示最小的,upp表示最大的。

之后连S到X,Y到T, 求从S到Y的可行流

求可行流时。。 添加附加源点ss,tt...

之后建图方式与  http://blog.csdn.net/hlyfalsy/article/details/38555467  SGU 176 类似。。


//tpl  
//ipqhjjybj_tpl.h  
//header.h  


#include <cstdio>  
#include <cstdlib>  
#include <map>  
#include <set>  
#include <algorithm>  
#include <cstring>  
#include <iostream>  
#include <vector>  
#include <string>  
#include <queue>  
#include <sstream>  
#include <math.h>  
  
#define mp(x,y) make_pair(x,y)  
#define pii pair<int,int>  
#define pLL pair<long long ,long long>  
#define pb(x) push_back(x)  
#define rep(i,j,k) for(int i = j; i < k;i++)  
  
#define MAX(x,a)  x=((x)<(a))?(a):(x)  
#define MIN(x,a)  x=((x)>(a))?(a):(x) 
  
using namespace std;  
  
const int N = 305;  
int n,m,tot;  
int s,t;  
int sum;  
struct node{  
    int u,v,w,next;  
    node(){}  
    node(int _u,int _v,int _w,int _next){  
        u=_u,v=_v,w=_w,next=_next;  
    }  
}edge[N*N];  
int head[N],cur[N],dis[N];  
int pre[N],gap[N],aug[N];  
const int oo=0x3f3f3f3f;  
void addEdge(int u,int v,int w){  
    edge[tot]=node(u,v,w,head[u]);  
    head[u]=tot++;  
    edge[tot]=node(v,u,0,head[v]);  
    head[v]=tot++;  
}  
  
int SAP(int s,int e,int n){  
    int max_flow=0,v,u=s;  
    int id,mindis;  
    aug[s]=oo;  
    pre[s]=-1;  
    memset(dis,0,sizeof(dis));  
    memset(gap,0,sizeof(gap));  
    gap[0]=n;  
  
    for(int i=0;i <= n;i++)  
        cur[i]=head[i];  
  
    while(dis[s]<n){  
        if(u==e){  
            max_flow += aug[e];  
            for(v=pre[e]; v!=-1; v=pre[v]){  
                int ed=cur[v];  
                edge[ed].w -= aug[e];  
                edge[ed^1].w += aug[e];  
                aug[v]-=aug[e];  
                if(edge[ed].w==0) u=v;  
            }  
        }  
        bool flag=false;  
        for(id=cur[u]; id!=-1;id=edge[id].next){  
            v=edge[id].v;  
            if(edge[id].w > 0 && dis[u]==dis[v]+1){  
                flag=true;  
                pre[v]=u;  
                cur[u]=id;  
                aug[v]=min(aug[u],edge[id].w);  
                u=v;  
                break;  
            }  
        }  
        if(flag==false){  
            if(--gap[dis[u]] == 0) break;   
            int mindis=n;  
            for(id=head[u]; id!=-1; id=edge[id].next){  
                v=edge[id].v;  
                if(edge[id].w>0 && dis[v] < mindis){  
                    mindis = dis[v];  
                    cur[u]=id;  
                }  
            }  
            dis[u] = mindis + 1;  
            gap[dis[u]]++;  
            if(u!=s)u=pre[u];  
        }  
    }  
    return max_flow;  
}  
int r[N],c[N];
int bom[N][N],upp[N][N];
int in[N];
int fs;
void print(){
	int row = 1;
	int col = 1;
	for(int i = 1;i < fs;i+=2){
		printf("%d",edge[i].w+bom[row][col]);
		if(col == m){
			row++;
			col = 1;
			printf("\n");
		}else {
			col++;
			printf(" ");
		}
	}
}
int solve(){
	int src = s , des = t;
	s = des+1, t = s+1;	
	int max_flow = 0;
	rep(i,0,des+1)
		if(in[i] > 0)addEdge(s,i,in[i]),max_flow+=in[i];
		else if(in[i] < 0) addEdge(i,t,-in[i]);
	// printf("max_flow = %d\n",max_flow);
	// printf("s=%d t=%d src=%d des=%d \n",s,t,src,des);
	int s1 = SAP(s,t,t+1);
	addEdge(des,src,oo);
	int s2 = SAP(s,t,t+1);
	// printf("s1=%d s2=%d\n",s1,s2);
	if(s1 + s2 == max_flow) return 1;
	else return -1;
}
int main(){
	int cas;
	int hang_flag = true;
	scanf("%d",&cas);
	while(cas--){
		if(hang_flag)hang_flag = false;
		else printf("\n");
		scanf("%d %d",&n,&m);
		memset(head,-1,sizeof(head));
		memset(in,0,sizeof(in));
		tot = s  = sum  =0;
		rep(i,1,n+1) scanf("%d",r+i);
		rep(i,1,m+1) scanf("%d",c+i);
		memset(bom,0,sizeof(bom));
		rep(i,1,n+1)
			rep(j,1,m+1)
				upp[i][j] = oo;
		int q;
		scanf("%d",&q);
		char op[10];
		bool flag = true;
		while(q--){
			int u,v,w;
			scanf("%d %d %s %d",&u,&v,op,&w);
			int tu1 = u ,tu2 = u , tv1 = v,tv2 = v;
			if(u == 0) tu1 = 1,tu2 = n;
			if(v == 0) tv1 = 1,tv2 = m;
			rep(i,tu1,tu2+1)
				rep(j,tv1,tv2+1){
					if(op[0] == '<') if(bom[i][j]>=w)flag=false; else MIN(upp[i][j],w-1);
					else if(op[0] == '>') if(upp[i][j]<=w)flag=false; else MAX(bom[i][j],w+1);
					else if(bom[i][j]>w||upp[i][j]<w)flag = false; else upp[i][j] = bom[i][j] = w;
				}
		}
		if(flag){
			t = n+m+1;
			rep(i,1,n+1)
				rep(j,1,m+1){
					addEdge(i,n+j,upp[i][j] - bom[i][j]);
					in[j+n] += bom[i][j];
					in[i] -= bom[i][j];
					if(upp[i][j] < bom[i][j])
						flag = false;
				}
			fs = tot;
			rep(i,1,n+1)
				addEdge(s,i,0),in[i]+=r[i],in[s]-=r[i];
			rep(i,1,m+1)
				addEdge(i+n,t,0),in[i+n]-=c[i],in[t]+=c[i];
		}
		if(flag && solve() >= 0){
			print();
		}else{
			puts("IMPOSSIBLE");
		}
	}
	return 0;
}


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值