下界为各数下取整的值,取差建立超级源汇点SS,TT跑一遍dinic,先判断是否可以满流,然后再跑原图,ans*3(原值算一遍,右边算一遍,下边算一遍)
详见代码
#include
#include
#include
#include
#define inf 0x7fffffff
#define db double
using namespace std;
db a[102][102];
int n,S,T,SS,TT,tot=1,in[225],d[225],sum,ans;
int head[250],cur[250],to[1000005],nxt[1000005],w[1000005];
queue<int>Q;
inline void lk(int u,int v,int val)
{to[++tot]=v;nxt[tot]=head[u];head[u]=tot;w[tot]=val;}
inline int imin(int x,int y){return x>y?y:x;}
inline void build()
{
int i,j;
for(i=1;i<=n;++i){
if(a[i][n]!=(int)a[i][n]) lk(S,i,1),lk(i,S,0);
in[S]-=(int)a[i][n];in[i]+=(int)a[i][n];
}
for(i=1;i<=n;++i){
if(a[n][i]!=(int)a[n][i]) lk(i+n,T,1),lk(T,i+n,0);
in[i+n]-=(int)a[n][i];in[T]+=(int)a[n][i];
}
for(i=1;ifor(j=1;jif(a[i][j]!=(int)a[i][j]) lk(i,j+n,1),lk(j+n,i,0);
in[i]-=(int)a[i][j];in[j+n]+=(int)a[i][j];
}
for(i=1;i<=TT;++i){
if(in[i]>0){sum+=in[i];lk(SS,i,in[i]);lk(i,SS,0);}
else if(in[i]<0)lk(i,TT,-in[i]),lk(TT,i,0);
}
}
inline bool bfs(int s,int t)
{
int I,J;
for(I=1;I<=TT;++I) d[I]=-1;
d[s]=0;Q.push(s);int x;
while(!Q.empty()){
x=Q.front();Q.pop();
for(I=head[x];I;I=nxt[I]){
J=to[I];
if(d[J]==-1 && w[I]){
d[J]=d[x]+1;
Q.push(J);
}
}
}
return d[t]!=-1?;
}
inline int dfs(int s,int t,int f)
{
if(s==t) return f;
int ss=0,ret;
for(int i=cur[s],j;i;i=nxt[i]){
j=to[i];
if(d[j]==d[s]+1 && w[i]){
ret=f-ss;ret=dfs(j,t,imin(ret,w[i]));
w[i]-=ret;w[i^1]+=ret;if(w[i]) cur[s]=i;
ss+=ret;if(ss==f) return f;
}
}
if(!ss) d[s]=-1;
return ss;
}
inline void dinic(int s,int t)
{
while(bfs(s,t)){
for(int i=1;i<=TT;++i) cur[i]=head[i];
ans+=dfs(s,t,inf);
}
}
int main(){
int i,j;
scanf("%d",&n);
for(i=1;i<=n;++i)
for(j=1;j<=n;++j) scanf("%lf",&a[i][j]);
S=(n<<1)+1;T=S+1;SS=T+1;TT=SS+1;
build();
lk(T,S,inf);lk(S,T,0);
dinic(SS,TT);
if(ans!=sum){printf("NO\n");return 0;}
ans=0;dinic(S,T);
printf("%d\n",ans*3);
}