最小割水题。入点向白点连边,白点向白点、黑点和空点连边,空点向空点和黑点连边,黑点向黑点和汇点连边。然后跑最大流即可。
话说Fd最近怎么光做水题啊……一点用都没有……qwq
我太菜了,做完一道题就打十来分钟osu……这么颓下去吃枣药丸
#include<cstdio>
#include<cstring>
#include<algorithm>
#include<cctype>
#include<cstdlib>
#include<queue>
#define maxn 10020
#define maxm 200200
using namespace std; int u[]={,,,-,};
int w[]={,,,,-};
int n,m; inline long long read(){
long long num=,f=;
char ch=getchar();
while(!isdigit(ch)){
if(ch=='-') f=-;
ch=getchar();
}
while(isdigit(ch)){
num=num*+ch-'';
ch=getchar();
}
return num*f;
} struct Edge{
int next,to,val;
}edge[maxm];
int head[maxn],num;
inline void addedge(int from,int to,int val){
edge[++num]=(Edge){head[from],to,val};
head[from]=num;
}
inline void add(int from,int to,int val){
addedge(from,to,val);
addedge(to,from,);
} inline int count(int i){ return i&?i+:i-; }
inline int calc(int i,int j){ return (i-)*m+j; } bool vis[maxn];
int dfn[maxn];
int list[maxn];
int Start,End; bool bfs(){
memset(vis,,sizeof(vis));
queue<int>q; q.push(Start); vis[Start]=; dfn[Start]=;
while(!q.empty()){
int from=q.front(); q.pop();
for(int i=head[from];i;i=edge[i].next){
int to=edge[i].to;
if(vis[to]||edge[i].val==) continue;
vis[to]=; dfn[to]=dfn[from]+;
q.push(to);
}
}
return vis[End];
} int dfs(int x,int val){
if(x==End||val==) return val;
int flow=; vis[x]=;
for(int &i=list[x];i;i=edge[i].next){
int to=edge[i].to;
if(vis[to]||edge[i].val==||dfn[to]!=dfn[x]+) continue;
int now=dfs(to,min(val,edge[i].val));
val-=now; edge[i].val-=now; edge[count(i)].val+=now; flow+=now;
if(val<=) break;
}
if(flow!=val) dfn[x]=-;
return flow;
} inline int maxflow(){
int ans=;
while(bfs()){
memset(vis,,sizeof(vis));
for(int i=Start;i<=End;++i) list[i]=head[i];
int now=dfs(Start,0x7fffffff);
if(now==) break;
ans+=now;
}
return ans;
} int q[][]; int main(){
n=read(),m=read(); End=n*m+;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j){
q[i][j]=read();
if(q[i][j]!=) q[i][j]=-q[i][j];
if(q[i][j]==) add(Start,calc(i,j),0x7fffffff);
else if(q[i][j]==) add(calc(i,j),End,0x7fffffff);
}
for(int i=;i<=n;++i)
for(int j=;j<=m;++j){
int now=calc(i,j);
for(int k=;k<=;++k){
int a=i+u[k],b=j+w[k];
if(a&&b&&a<=n&&b<=m){
int ret=calc(a,b);
if(q[i][j]>=q[a][b]) add(now,ret,);
}
}
}
printf("%d",maxflow());
return ;
}