宫廷守卫

题目链接:

  P1263 宫廷守卫

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('\n');}

 

posted @ 2020-08-12 21:26  月落乌啼算钱  阅读(155)  评论(0编辑  收藏  举报