[luogu1263]宫廷守卫(二分图最大匹配)

题目

传送门

大意:n*m格子有墙和陷阱,墙能遮挡视线,往空地上放守卫保证守卫不能互相看到

Solution

比较经典的匹配问题,将行和列分段(跟据墙)分别设为左部点和右部点,空地代表行和列有连边,然后跑二分图最大匹配就完了。

Code

第一次上传code稍微加一下注释吧~

//By zuiyumeng
#pragma GCC optimize(2)
#include <set>
#include <map>
#include <cmath>
#include <cstdio>
#include <cstdlib>
#include <cstring>
#include <iostream>
#include <algorithm>
#define Re register
#define Ms(a,b) memset((a),(b),sizeof(a))
#define Fo(i,a,b) for(Re int i=(a),_=(b);i<=_;i++)
#define Ro(i,a,b) for(Re int i=(b),_=(a);i>=_;i--)
// #define getchar() (p1==p2&&(p2=(p1=buf)+fread(buf,1,1<<21,stdin)),p1==p2?EOF:*p1++)
using namespace std;
typedef long long LL;
typedef pair<int,int> PII;

char buf[1<<21],*p1,*p2;
inline int read() { 
    int x=0,f=1;char c=getchar();
    while(!isdigit(c)) {if(c=='-')f=-f;c=getchar();}
    while(isdigit(c)) x=(x<<1)+(x<<3)+(c^48),c=getchar();
    return x*f;
}
//上面是常用头文件可忽略qwq
const int N=210;
int n,m,cntl,cntn,now,ans;
int a[N][N],b[N][N],lx[N][N];//a为原数组(0空地1陷阱2墙),b为列号,lx为行号(用c会报错= =)
int head[N*N*2],vis[N*N*2],mat[N*N*2],nxt[N*N*2],to[N*N*2];//mat表示匹配点
//邻接表算不清楚的话尽量开大一些TAT,否则容易RE
void add(int u,int v) {
    nxt[++cntl]=head[u]; to[cntl]=v; head[u]=cntl;
    nxt[++cntl]=head[v]; to[cntl]=u; head[v]=cntl;
}

bool hun(int u) {//匈牙利算法~
    for(int i=head[u],v;i;i=nxt[i]) {
        if(vis[(v=to[i])]==now) continue;
        vis[v]=now;
        if(!mat[v] || hun(mat[v])) {mat[v]=u; return 1;}
    }
    return 0;
}

int main() {
    n=read(),m=read();
    Fo(i,1,n) Fo(j,1,m) a[i][j]=read();
    Fo(j,1,m) {
        int tmp=++cntn;
        Fo(i,1,n) {
            if(a[i][j]==2) tmp=cntn=cntn+(a[i-1][j]!=2);//尽量减少点的数量防止RE(结果还是RE了一次= =)
            else if(a[i][j]==0) b[i][j]=tmp;
        }
    }
    Fo(i,1,n) {
        int tmp=++cntn;
        Fo(j,1,m) {
            if(a[i][j]==2) tmp=cntn=cntn+(a[i][j-1]!=2);
            else if(a[i][j]==0) lx[i][j]=tmp,add(tmp,b[i][j]);
        }
    }
    now=1;
    for(int i=1;i<=cntn;i++,now++) if(hun(i)) ans++;
    printf("%d\n",ans/2);
    Fo(i,1,n) Fo(j,1,m) if(mat[b[i][j]]&&mat[b[i][j]]==lx[i][j]) printf("%d %d\n",i,j);
    return 0;
}

后记

既然做了一道二分图,那么接下来就整理一下二分图的知识吧qwq~

posted @ 2020-08-30 18:00  醉语梦  阅读(151)  评论(0编辑  收藏  举报