【Luogu】P2598狼和羊的故事(最小割转最大流)
最小割水题。入点向白点连边,白点向白点、黑点和空点连边,空点向空点和黑点连边,黑点向黑点和汇点连边。然后跑最大流即可。
话说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[5]={0,1,0,-1,0}; int w[5]={0,0,1,0,-1}; int n,m; inline long long read(){ long long num=0,f=1; char ch=getchar(); while(!isdigit(ch)){ if(ch=='-') f=-1; ch=getchar(); } while(isdigit(ch)){ num=num*10+ch-'0'; 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,0); } inline int count(int i){ return i&1?i+1:i-1; } inline int calc(int i,int j){ return (i-1)*m+j; } bool vis[maxn]; int dfn[maxn]; int list[maxn]; int Start,End; bool bfs(){ memset(vis,0,sizeof(vis)); queue<int>q; q.push(Start); vis[Start]=1; dfn[Start]=1; 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==0) continue; vis[to]=1; dfn[to]=dfn[from]+1; q.push(to); } } return vis[End]; } int dfs(int x,int val){ if(x==End||val==0) return val; int flow=0; vis[x]=1; for(int &i=list[x];i;i=edge[i].next){ int to=edge[i].to; if(vis[to]||edge[i].val==0||dfn[to]!=dfn[x]+1) 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<=0) break; } if(flow!=val) dfn[x]=-1; return flow; } inline int maxflow(){ int ans=0; while(bfs()){ memset(vis,0,sizeof(vis)); for(int i=Start;i<=End;++i) list[i]=head[i]; int now=dfs(Start,0x7fffffff); if(now==0) break; ans+=now; } return ans; } int q[202][202]; int main(){ n=read(),m=read(); End=n*m+1; for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ q[i][j]=read(); if(q[i][j]!=2) q[i][j]=1-q[i][j]; if(q[i][j]==2) add(Start,calc(i,j),0x7fffffff); else if(q[i][j]==0) add(calc(i,j),End,0x7fffffff); } for(int i=1;i<=n;++i) for(int j=1;j<=m;++j){ int now=calc(i,j); for(int k=1;k<=4;++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,1); } } } printf("%d",maxflow()); return 0; }