有上下界最大流
不会打,蒟蒻就打了二分
UPD:http://hzwer.com/3703.html 黄学长的最大流 我这个傻逼既然还打了二分
#include<cstdio>
#include<cstdlib>
#include<algorithm>
#include<cstring>
using namespace std;
namespace DINIC{
#define oo 1<<30
#define V G[p].v
#define cl(x) memset(x,0,sizeof(x))
#define M 50000+5
#define N 500+5
struct edge{
int u,v,f;
int next;
};
edge G[M];
int head[N],num=1;
inline void add(int u,int v,int f,int p){
G[p].u=u; G[p].v=v; G[p].f=f; G[p].next=head[u]; head[u]=p;
}
inline void link(int u,int v,int f){
add(u,v,f,num+=2); add(v,u,0,num^1);
}
int S,T;
int Que[N],l,r;
int dis[N];
inline bool bfs(){
int u;
memset(dis,-1,sizeof(dis)); cl(Que); l=r=-1;
dis[S]=1; Que[++r]=S;
while (l<r)
{
u=Que[++l];
for (int p=head[u];p;p=G[p].next)
if (G[p].f && dis[V]==-1)
{
dis[V]=dis[u]+1;
Que[++r]=V;
if (V==T) return true;
}
}
return false;
}
int minimum;
int cur[N];
inline bool dfs(int u,int mini){
if (u==T) { minimum=mini; return true; }
for (int p=cur[u];p;p=G[p].next)
{
cur[u]=p;
if (G[p].f && dis[V]==dis[u]+1 && dfs(V,min(mini,G[p].f)))
{
G[p].f-=minimum; G[p^1].f+=minimum;
return true;
}
}
dis[u]=-1;
return false;
}
inline int Dinic(){
int ret=0;
while (bfs())
{
memcpy(cur,head,sizeof(cur));
while (dfs(S,oo))
ret+=minimum;
}
return ret;
}
inline void clear(){
cl(G); cl(head); num=1;
}
}
int n;
double a[105][105];
int du[215];
inline bool check(int mid){
using namespace DINIC;
clear();
S=2*n+1; T=2*n+2;
int s=2*n-1,t=2*n;
link(t,s,oo);
memset(du,0,sizeof(du));
du[t]-=mid; du[s]+=mid;
for(int i=1;i<n;i++)
{
if(a[i][n]!=(int)a[i][n])
link(s,i,1);
du[s]-=(int)a[i][n]; du[i]+=(int)a[i][n];
}
for(int i=1;i<n;i++)
{
if(a[n][i]!=(int)a[n][i])
link(i+n-1,t,1);
du[i+n-1]-=(int)a[n][i]; du[t]+=(int)a[n][i];
}
for(int i=1;i<n;i++)
for(int j=1;j<n;j++)
{
if(a[i][j]!=(int)a[i][j])
link(i,j+n-1,1);
du[i]-=(int)a[i][j]; du[j+n-1]+=(int)a[i][j];
}
int tot=0;
for (int i=1;i<=2*n;i++)
if(du[i]>0)
tot+=du[i],link(S,i,du[i]);
else
link(i,T,-du[i]);
int itmp=Dinic();
if (itmp==tot) return true;
return false;
}
int main()
{
double isum=0;
freopen("t.in","r",stdin);
freopen("t.out","w",stdout);
scanf("%d",&n);
for (int i=1;i<=n;i++)
for (int j=1;j<=n;j++)
{
scanf("%lf",&a[i][j]);
isum+=a[i][j];
}
int L=0,R=(int)isum+n*n+10,MID;
while (L+1<R)
if (check(MID=(L+R)>>1))
L=MID;
else
R=MID;
printf("%d\n",L*3);
}