[BZOJ3698]XWW的难题解题报告|上下界网络流|有源汇最大流
XWW是个影响力很大的人,他有很多的追随者。这些追随者都想要加入XWW教成为XWW的教徒。但是这并不容易,需要通过XWW的考核。
XWW给你出了这么一个难题:XWW给你一个N*N的正实数矩阵A,满足XWW性。
称一个N*N的矩阵满足XWW性当且仅当:(1)A[N][N]=0;(2)矩阵中每行的最后一个元素等于该行前N-1个数的和;(3)矩阵中每列的最后一个元素等于该列前N-1个数的和。
现在你要给A中的数进行取整操作(可以是上取整或者下取整),使得最后的A矩阵仍然满足XWW性。同时XWW还要求A中的元素之和尽量大。
首先很容易看出这是一个带上下界的网络流题...
源点向代表每一行的点连边,代表每一列的点向汇点连边
每一行向每一列连边,连的边就如前面无源汇可行流一样
然后由于求的是最大流,二分答案
每次从t→s连一条下限为mid的边
问题来了..最后要输出的和最终的mid有什么关系呢...
我们考虑这张图上的流量代表什么
我们连的边代表的刚开始没有考虑下限的边所以认为是波动的数值
然而实际上很简单就是每个格子的数值
最后输出的答案是整张图的数值
每个点在自己位置、行末和列末各统计一次
所以乘上3输出就可以了
因为INF设得过小WA了两次...
program zoj2314; const maxn = 2100;maxm = 800010;INF = 100000007; var fa,next,ter,w,rec,flow:array[-1..maxm]of longint; link,dis,opt,inp:array[-1..maxn]of longint; vis:array[-1..maxn]of boolean; n,m,e,tt,test,i,s,t,x,y,l,r,j,mid,sum,lx,rx,ans:longint; a:array[-1..maxn,-1..maxn]of extended; function min(a,b:longint):longint; begin if a<b then exit(a) else exit(b); end; function spfa:boolean; var head,tail,x,j:longint; begin fillchar(vis,sizeof(vis),true); fillchar(dis,sizeof(dis),63); head:=0;tail:=1;opt[1]:=s;vis[s]:=false;dis[s]:=0; while head<>tail do begin head:=(head+1) mod maxn; x:=opt[head];j:=link[x]; while j<>0 do begin if (dis[x]+1<dis[ter[j]])and(w[j]>0) then begin dis[ter[j]]:=dis[x]+1; if vis[ter[j]] then begin vis[ter[j]]:=false; tail:=(tail+1) mod maxn; opt[tail]:=ter[j]; end; end; j:=next[j]; end; vis[x]:=true; end; if dis[t]<>dis[t+1] then exit(true) else exit(false); end; function dfs(p,sum:longint):longint; var tem,j,x:longint; begin tem:=0; if p=t then exit(sum); j:=link[p]; while j<>0 do begin if (dis[ter[j]]=dis[p]+1)and(w[j]>0) then begin x:=dfs(ter[j],min(sum-tem,w[j])); inc(tem,x);dec(w[j],x);inc(w[rec[j]],x); if rec[j]=j+1 then inc(flow[fa[j]],x) else dec(flow[fa[rec[j]]],x); if tem=sum then exit(sum); end; j:=next[j]; end; exit(tem); end; procedure add(x,y,z:longint); begin inc(e);ter[e]:=y;next[e]:=link[x];link[x]:=e;w[e]:=z;rec[e]:=e+1; inc(e);ter[e]:=x;next[e]:=link[y];link[y]:=e;w[e]:=0;rec[e]:=e-1; end; function Jud:boolean; var j:longint; begin j:=link[s]; while j<>0 do begin if w[j]>0 then exit(false); j:=next[j]; end; exit(true); end; function Solve:boolean; var i,sum:longint; begin sum:=0; while spfa do inc(sum,dfs(s,1000000007)); if (not Jud) then exit(false) else exit(true); end; begin readln(n);ans:=0; for i:=1 to n do begin for j:=1 to n do begin read(a[i,j]);inc(ans,trunc(a[i,j]));end; readln; end; Lx:=0;Rx:=10000000007;sum:=-1; while Lx<=Rx do begin mid:=(Lx+Rx) >> 1; fillchar(next,sizeof(next),0); fillchar(link,sizeof(link),0); fillchar(inp,sizeof(inp),0); e:=0;s:=0 ;t:=2*n+1; for i:=1 to n-1 do begin l:=trunc(a[i,n]); if a[i,n]<>l then add(s,i,1); dec(inp[s],l);inc(inp[i],l); l:=trunc(a[n,i]); if a[n,i]<>l then add(n+i,t,1); dec(inp[n+i],l);inc(inp[t],l); end; for i:=1 to n-1 do for j:=1 to n-1 do begin l:=trunc(a[i,j]); if a[i,j]<>l then add(i,n+j,1); dec(inp[i],l);inc(inp[n+j],l); end; add(t,s,INF); inc(inp[s],mid);dec(inp[t],mid); dec(s);inc(t); for i:=s+1 to t-1 do if inp[i]>0 then add(s,i,inp[i]) else if inp[i]<0 then add(i,t,-inp[i]); if Solve then begin sum:=mid;Lx:=mid+1 end else Rx:=mid-1; end; writeln(sum*3); end.