题目描述
Description
Input
Output
Sample Input
2 2
0 1
2 1
0 1
Sample Output
1
1 1
1 1
Data Constraint
上下界网络流
就是像普通的网络流那样,只不过每条边都有一个下界,要求每条边的流都至少要达到这个下界
因为每条边都要达到下界,所以考虑把下界单独变成一条弧,剩下的就是流量为(上界-下界)的边
显然这样和原图是等价的
每个下界都要求满流,所以每条红色边都要满,考虑把所有红色边拉出来单独考虑
根据流量平衡,每个点的入=出,所以先把每个点分配等同于入度的流(满足下界),然后让其流到其它点,使每个点满足流量平衡,如果可以流满则可以满足流量平衡
新建一个超级源和超级汇,然后由超级源向每个点连等同于下界入度的边(流入),由每个点向超级汇连等同于下界出度的边(流出)
但是由于原图有源汇,也就是说可以向s流入一个流,再从t流出等价的流
显然t流出多少s就流入多少,也就相当于由t向s连了一条流量为+∞的边
最后以y为源点,x为汇点做最大流,判断连向x的边是否满流,如果满流则可以满足要求
100%
显然最终的答案为max(|a每行的和-b每行的和|,|a每列的和-b每列的和|),考虑二分这个答案ans
则每行就相当于有ans的容错,也就是说
a每行的和-ans≤b每行的和≤a每行的和+ans
列同理
所以由源点向每一行连向[该行的和-ans,该行的和+ans],由每一行向每一列连向[L,R],由每一列向汇点连向[该列的和-ans,该列的和+ans],然后判断是否有可行流
由源点向每一行和由每一列向汇点连边,就相当于规定了该行/列的总和范围,然后每个数都在[L,R]的范围内,就是行与列之间的连边
因为边比较多,所以可以把上/下界累加到一起最后一起连边
code
我以前写的sap和dinic都是假的
可以参考cold_chair大佬的网络流模板
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
#define fo(a,b,c) for (a=b; a<=c; a++)
#define fd(a,b,c) for (a=b; a>=c; a--)
#define max(a,b) (a>b?a:b)
#define min(a,b) (a<b?a:b)
using namespace std;
int A[201];
int B[201];
int a[400001][3];
int ls[501];
int cur[501];
int f[501];
int g[501];
int d[10001];
int in[501];
int out[501];
int n,m,i,j,k,l,r,mid,len,L,R,sum,begin,end;
int ans;
void New(int x,int y,int z)
{
++len;
a[len][0]=y;
a[len][1]=z;
a[len][2]=ls[x];
ls[x]=len;
}
void NEW(int x,int y,int l,int r)
{
New(x,y,r-l);
New(y,x,0);
in[y]+=l;
out[x]+=l;
// New(x,n+m+3,l);
// New(n+m+3,x,0);
// New(n+m+2,y,l);
// New(y,n+m+2,0);
sum+=l;
}
void bfs()
{
int h=0,t=1,i;
f[end]=0;
d[1]=end;
while (h<t)
{
for (i=ls[d[++h]]; i; i=a[i][2])
if (a[i^1][1] && f[a[i][0]]>f[d[h]]+1)
{
f[a[i][0]]=f[d[h]]+1;
d[++t]=a[i][0];
}
}
fo(i,0,end) if (f[i]>2333) f[i]=n+m+4;
fo(i,0,end) ++g[f[i]];
}
int dfs(int t,int flow)
{
int F=0,i,Flow;
if (t==end) return flow;
for (i=cur[t]; i; i=a[i][2])
if (a[i][1] && f[t]==f[a[i][0]]+1)
{
Flow=dfs(a[i][0],min(flow-F,a[i][1]));
F+=Flow;
a[i][1]-=Flow;
a[i^1][1]+=Flow;
cur[t]=i;
if (F==flow) return flow;
}
cur[t]=ls[t];
if (!(--g[f[t]++]))
{
f[begin]=n+m+4;
return F;
}
++g[f[t]];
return F;
}
bool pd(int t)
{
int i,j;
memset(ls,0,sizeof(ls));
memset(f,1,sizeof(f));
memset(g,0,sizeof(g));
memset(in,0,sizeof(in));
memset(out,0,sizeof(out));
len=1;
sum=0;
fo(i,1,n)
{
fo(j,1,m)
NEW(i,n+j,L,R);
}
fo(i,1,n)
NEW(0,i,max(A[i]-t,0),A[i]+t);
fo(i,1,m)
NEW(n+i,n+m+1,max(B[i]-t,0),B[i]+t);
NEW(n+m+1,0,0,233333333);
fo(i,0,end)
{
New(begin,i,in[i]);
New(i,begin,0);
New(i,end,out[i]);
New(end,i,0);
cur[i]=ls[i];
}
g[0]=n+m+4;
bfs();
ans=0;
while (f[begin]<=n+m+3)
ans+=dfs(begin,233333333);
return ans==sum;
}
int main()
{
scanf("%d%d",&n,&m);len=1;
begin=n+m+2;
end=n+m+3;
fo(i,1,n)
{
fo(j,1,m)
{
scanf("%d",&k);
A[i]+=k;
B[j]+=k;
}
}
scanf("%d%d",&L,&R);
l=0;
r=200000;
while (l<r)
{
mid=(l+r)/2;
if (!pd(mid))
l=mid+1;
else
r=mid;
}
printf("%d\n",l);
pd(l);
k=3;
fo(i,1,n)
{
fo(j,1,m)
printf("%d ",a[k][1]+L),k+=2;
printf("\n");
}
}