题目链接:
solution:
欲解决此题,我们先来看一个简化版的问题.有$n$行$m$列的矩阵,每行每列只能放一个士兵,试问最多能放多少个士兵.这种题目是最经典的二分图最大匹配问题,考虑到每行每列均只能放一只兵,我们不妨建立两部分点,第一部分为行,第二部分为列,行列之间的边流量表示此行此列可放一只兵,然后每行每列只能放一只这个条件直接通过超源超汇限流控制即可.
回到本题,只需将连续的小行小列编上号,即可转化为上述问题.
#include<iostream> #include<cstdio> #include<cstdlib> #include<cstring> #include<cmath> #include<algorithm> #include<queue> #include<map> #include<set> #include<vector> #define R register #define next kdjadskfj #define debug puts("mlg") #define mod 998244353 #define Mod(x) ((x%mod+mod)%mod) using namespace std; typedef long long ll; typedef long double ld; typedef unsigned long long ull; inline ll read(); inline void write(ll x); inline void writeln(ll x); inline void writesp(ll x); ll n,m; ll Map[210][210]; ll vis1[210][210],vis2[210][210],cnt,tot1,tot2; ll fid[210*210*2]; ll S,T; namespace Dinic{ ll c[1000000],to[1000000],head[1000000],next[1000000],tot=1; inline void add(ll x,ll y,ll z){ to[++tot]=y;next[tot]=head[x];head[x]=tot;c[tot]=z; } inline void Link(ll x,ll y,ll z){ add(x,y,z);add(y,x,0); } ll d[1000000]; queue<ll>q; inline bool bfs(){ memset(d,0,sizeof d); while(!q.empty())q.pop(); q.push(S);d[S]=1; while(!q.empty()){ ll x=q.front(); q.pop(); for(R ll i=head[x],ver;i;i=next[i]){ ver=to[i]; if(!d[ver]&&c[i]){ q.push(ver); d[ver]=d[x]+1; if(ver==T) return true; } } } return false; } inline ll dinic(ll x,ll flow){ if(x==T||!flow) return flow; ll rest=flow,k; for(R ll i=head[x],ver;i&&rest;i=next[i]){ ver=to[i]; if(d[ver]==d[x]+1&&c[i]){ k=dinic(ver,min(c[i],rest)); if(!k) d[ver]=0; rest-=k; c[i]-=k; c[i^1]+=k; } } return flow-rest; } inline void solve(){ ll ans=0,_flow; while(bfs()){ while(_flow=dinic(S,0x7fffffff)) ans+=_flow; } writeln(ans); for(R ll i=1;i<=tot1;i++){ for(R ll j=head[i],ver;j;j=next[j]){ ver=to[j]; if(ver>cnt) continue; if(!c[j]) writesp(fid[i]),writeln(fid[ver]); } } exit(0); } } int main(){ n=read();m=read(); for(R ll i=1;i<=n;i++){ for(R ll j=1;j<=m;j++){ Map[i][j]=read(); } } for(R ll i=1;i<=n;i++){ Map[i][0]=2; for(R ll j=1;j<=m;j++){ if(Map[i][j]==2) continue; if(Map[i][j-1]==2) vis1[i][j]=++cnt,fid[cnt]=i; else vis1[i][j]=cnt; } } tot1=cnt; for(R ll i=1;i<=m;i++){ Map[0][i]=2; for(R ll j=1;j<=n;j++){ if(Map[j][i]==2) continue; if(Map[j-1][i]==2) vis2[j][i]=++cnt,fid[cnt]=i; else vis2[j][i]=cnt; } } tot2=cnt; S=cnt+1;T=S+1; for(R ll i=1;i<=tot1;i++){ Dinic::Link(S,i,1); } for(R ll i=tot1+1;i<=tot2;i++){ Dinic::Link(i,T,1); } for(R ll i=1;i<=n;i++){ for(R ll j=1;j<=m;j++){ if(!Map[i][j]) Dinic::Link(vis1[i][j],vis2[i][j],1); } } Dinic::solve(); } inline ll read(){ll x=0,t=1;char ch=getchar();while(ch<'0'||ch>'9'){if(ch=='-') t=-1;ch=getchar();}while(ch>='0'&&ch<='9'){x=x*10+ch-'0';ch=getchar();}return x*t;} inline void write(ll x){if(x<0){putchar('-');x=-x;}if(x<=9){putchar(x+'0');return;}write(x/10);putchar(x%10+'0');} inline void writesp(ll x){write(x);putchar(' ');} inline void writeln(ll x){write(x);putchar(' ');}