这道题网上题解到处都是,在此就不赘述了。
看到这题时,我一开始的想法是对于每个点
Ai,j
(其中i!=n && j!=n
),向其所在行和列连边。
但这样是有问题的,因为可能行和列所连的边流量不同,这显然是不对的。
感觉网络流题目查错一般适合静态差错,因为网络流模板一般不太会打错,bug大多出在见图上,单步跟踪很难发现。
下面就是比q234rty大爷慢到不知道哪里去的代码。
upd:刚才突然发现自己不理解自己的做法了。
事实上,对于有源有汇有上下界的最大流,我在此的做法是先加附加源汇,跑一遍有源有汇有上下界的可行流,再在残量网络上跑最大流。本来答案应该是新增的流量加原始边的流量下界之和,但注意到t->s有一条(0,inf)的边,第一遍跑完后会产生流量为原始边的流量下界之和的反向边,然后第二遍时会把这条边的流量自动加上,就不必手动累加了。
#include <cstdio>
const int N=310,M=100010,inf=1<<30;
struct graph{
struct edge{
int to,next,flow;
edge(int _to=0,int _next=0,int _flow=0):to(_to),next(_next),flow(_flow){}
}e[M<<1];
int h[N],d[N],q[N],t,w,xb,n,cur[N],T;
void addedge(int x,int y,int z){
e[++xb]=edge(y,h[x],z);
h[x]=xb;
e[++xb]=edge(x,h[y],0);
h[y]=xb;
}
inline int o(int x){
if(x&1)return x+1;
else return x-1;
}
bool bfs(int x,int y){
for(int i=1;i<=n;++i)d[i]=cur[i]=0;d[x]=1;t=0;w=1;q[1]=x;
while(t<w){
int u=q[++t];
for(int i=h[u];i;i=e[i].next)
if(e[i].flow && !d[e[i].to]){
d[e[i].to] =d[u]+1;
q[++w]=e[i].to;
if(e[i].to==T)return 1;
}
}
return d[y];
}
inline int min(int x,int y){
return x<y?x:y;
}
int dfs(int x,int f){
if(x==T || !f)return f;int flow=0;
for(int&i=cur[x];i;i=e[i].next)if(e[i].flow && d[e[i].to]==d[x]+1){
int a=dfs(e[i].to,min(f,e[i].flow));
if(a){
e[i].flow-=a;e[o(i)].flow+=a;flow+=a;f-=a;
if(!f)break;
}
}
return flow;
}
int maxflow(int x,int y){
T=y;
int ans=0;
while(bfs(x,y)){
for(int i=1;i<=n;++i)cur[i]=h[i];
ans+=dfs(x,1<<30);
}
return ans;
}
}g;
int n,i,u[M],v[M],l[M],r[M],x,z,xb,j,k=1,out[M],s;
double y;
int main(){
scanf("%d",&n);
u[xb=1]=n<<1,v[1]=1,l[1]=0,r[xb]=inf;
for(i=1;i<=n;++i)
for(j=1;j<=n;++j){
scanf("%lf",&y);x=y;if(y<0 && x!=y)--x;z=x+(x!=y);
if(i==n && j==n)continue;l[++xb]=x,r[xb]=z;
if(j==n)u[xb]=1,v[xb]=i+1;
else if(i==n)u[xb]=j+n,v[xb]=n<<1;
else u[xb]=i+1,v[xb]=j+n;
}
for(i=1;i<=xb;++i)out[u[i]]+=l[i],out[v[i]]-=l[i];
for(i=1;i<=n<<1;++i)
if(out[i]>0)g.addedge(i,n*2+2,out[i]),s+=out[i];
else if(out[i])g.addedge(n<<1|1,i,-out[i]);
for(i=1;i<=xb;++i)if(l[i]<r[i])g.addedge(u[i],v[i],r[i]-l[i]);
g.n=n*2+2;
if(g.maxflow(n<<1|1,n*2+2)<s)return puts("No"),0;
printf("%d\n",g.maxflow(1,n<<1)*3);
return 0;
}