zoukankan      html  css  js  c++  java
  • [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
    ",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
    ",i,j);
        return 0;
    }
    

    后记

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

    本文版权归作者所有,未经允许不得转载。
  • 相关阅读:
    java基础知识回顾之final
    基础知识《十四》Java异常的栈轨迹fillInStackTrace和printStackTrace的用法
    基础知识《六》---Java集合类: Set、List、Map、Queue使用场景梳理
    基础知识《五》---Java多线程的常见陷阱
    基础知识《四》---Java多线程学习总结
    《转》如何选择合适的服务器托管商
    基础知识《三》java修饰符
    基础知识《零》---Java程序运行机制及运行过程
    应用 JD-Eclipse 插件实现 RFT 中 .class 文件的反向编译
    DOS命令符基本操作
  • 原文地址:https://www.cnblogs.com/zuiyumeng/p/13585989.html
Copyright © 2011-2022 走看看