POJ 2369 Budget【有上下界的最大流】
题意: 给出一个 n*m的矩阵,知道了每一行元素的和(n个),每一列元素的和(m个)
给出t个条件:
a b c d
表示 a b 和 数字 d 满足条件 c
分析: 此题的最大流有下界的限制,用上下界最大流求解时,需要先去掉下界,判断是否存在可行流
将 1 到 n 行每行看作一个节点(1..n),将 1 到 m 列每列看作一个节点(n+1..n+m)
建立源点 s=0,汇点 t=n+m+1
在源点 s 和每一个行节点之间连一条上界是行数字的和下界为 0的边
在每一个列节点和和汇点t之间连一条上界是列数字的和下界为 0的边
如果 i 行 j 列的数字大于 x,就在 i 行节点和 j 列节点之间连一条上界为INF,下界为 x+1 的边
如果 i 行 j 列的数字小于 x,就在 i 行节点和 j 列节点之间连一条上界为x-1, 下界为 0 的边
如果等于,上下界都是x
建图之后, i 行与 j 列的流量就是 i,j的值
如果最大流等于所有行元素的和,就存在解,输出流量即可。
#include<stdio.h> #include<string.h> #define clr(x)memset(x,0,sizeof(x)) #define maxn 300 #define INF 0x1f1f1f1f #define min(a,b)(a)<(b)?(a):(b) int cap[maxn][maxn]; int clow[maxn][maxn]; int flow[maxn][maxn]; void max_flow(int s,int t,int n) { int p[maxn],a[maxn],q[maxn]; int u,v,front,rear; for(;;) { clr(a); a[s]=INF; front=rear=0; q[rear++]=s; while(front<rear) { u=q[front++]; for(v=0;v<n;v++) if(!a[v]&&flow[u][v]<cap[u][v]) { p[v]=u; q[rear++]=v; a[v]=min(a[u],cap[u][v]-flow[u][v]); } } if(a[t]==0) break; for(u=t;u!=s;u=p[u]) { flow[p[u]][u]+=a[t]; flow[u][p[u]]-=a[t]; } } } int limit_flow(int s,int t,int n) { int i,j,sk,ks; if(s==t) return INF; cap[n][n+1]=cap[n+1][n]=cap[n][n]=cap[n+1][n+1]=0; for(i=0;i<n;i++) { cap[n][i]=cap[i][n]=cap[n+1][i]=cap[i][n+1]=0; for(j=0;j<n;j++) { cap[i][j]-=clow[i][j]; cap[n][i]+=clow[j][i]; cap[i][n+1]+=clow[i][j]; } } sk=cap[s][t]; ks=cap[t][s]; cap[s][t]=cap[t][s]=INF; max_flow(n,n+1,n+2); for(i=0;i<n;i++) if(flow[n][i]<cap[n][i]) return -1; flow[s][t]=flow[t][s]=0; cap[s][t]=sk; cap[t][s]=ks; max_flow(s,t,n); for(i=0;i<n;i++) for(j=0;j<n;j++) { cap[i][j]+=clow[i][j]; flow[i][j]+=clow[i][j]; } i=j=0; while(i<n) j+=flow[s][i++]; return j; } int main() { int sum1,sum2,s,i,j,t,T,tot,n,m; bool flag; scanf("%d",&T); while(T--) { scanf("%d%d",&n,&m); clr(cap); clr(clow); clr(flow); s=0; t=n+m+1; sum1=sum2=0; for(i=1;i<=n;i++) for(j=1;j<=m;j++) cap[i][j+n]=INF; for(i=1;i<=n;i++) { scanf("%d",&cap[s][i]); sum1+=cap[s][i]; } for(i=n+1;i<=n+m;i++) { scanf("%d",&cap[i][t]); sum2+=cap[i][t]; } flag=true; scanf("%d",&tot); while(tot--) { int a,b,w; int f1,f2,t1,t2; char ch[2]; scanf("%d%d%s%d",&a,&b,ch,&w); f1=t1=a; f2=t2=b; if(a==0){ f1=1; t1=n; } if(b==0){ f2=1; t2=m; } for(i=f1;i<=t1;i++) for(j=f2;j<=t2;j++) { if(ch[0]=='='){ cap[i][j+n]=clow[i][j+n]=w; if(cap[s][i]<w||cap[j+n][t]<w) flag=false; } else if(ch[0]=='>'&&clow[i][j+n]<w+1) { clow[i][j+n]=w+1; if(cap[s][i]<w+1||cap[j+n][t]<w+1) flag=false; } else if(ch[0]=='<'&&cap[i][j+n]>w-1) cap[i][j+n]=w-1; } } if(sum1==sum2&&flag) { clr(flow); int rflow=limit_flow(s,t,t+1); if(rflow!=-1&&rflow==sum1) { for(i=1;i<=n;i++) for(j=1;j<=m;j++) printf("%d%c",flow[i][j+n],j==m?'\n':' '); } else printf("IMPOSSIBLE\n"); } else printf("IMPOSSIBLE\n"); } return 0; }