• [poj2446]Chessboard


    Description

    给定一个\(m\;\times\;n\)的棋盘,上面有\(k\)个洞,求是否能在不重复覆盖且不覆盖到洞的情况下,用\(2\;\times\;1\)的卡片完全覆盖棋盘。

    Input

    第一行有三个整数\(n,m,k(0<m,n\;\leq\;32,0\;\leq\;k<m\;\times\;n),m\)表示行数,\(n\)表示列数。

    接下来\(k\)行,每行两个整数\(y,x\),表示\((x,y)\)上有个洞。

    Output

    如果能覆盖,输出\(YES\);否则输出\(NO\)

    Sample Input

    4 3 2
    2 1
    3 3
    

    Sample Output

    YES
    

    Solution

    \(32\;\times\;32\)的范围如果暴搜剪枝能力比较强的人也许能过吧,但是我并没有那个能力。

    \(2\;\times\;1\)的卡片去覆盖的话,就是两个相邻的格子为一对,且每个格子只能属于一对(有洞的格子不属于任何一对)。

    怎么有点像二分图匹配?那就想想怎么构图吧。

    定义两格子相邻当且仅当它们有一条公共边时。

    那么两个相邻的格子就得在不同集合里,按这样分正好能分成两个集合。

    然后两个可放卡片的相邻格子连一条边,这样二分图就构成功了。

    #include<set> 
    #include<cmath>
    #include<ctime>
    #include<queue>
    #include<stack>
    #include<cstdio>
    #include<vector>
    #include<cstring>
    #include<cstdlib>
    #include<iostream>
    #include<algorithm>
    #define D 5 
    #define N 35
    #define K 513
    #define M 2049
    using namespace std;
    struct graph{
        int nxt,to;
    }e[M];
    int x[D]={0,0,0,1,-1},y[D]={0,1,-1,0,0};
    int g[K],fr[N*N],m,n,k,cnt,tot,sum;
    bool b[N][N],u[N*N];
    inline void addedge(int x,int y){
        e[++cnt].nxt=g[x];g[x]=cnt;e[cnt].to=y;
    }
    inline bool match(int k){
        for(int i=g[k];i;i=e[i].nxt)
            if(!u[e[i].to]){
                u[e[i].to]=true;
                if(!fr[e[i].to]||match(fr[e[i].to])){
                    fr[e[i].to]=k;return true;
                }
            }
        return false;
    }
    inline bool hungary(){
        for(int i=1;i<=tot;i++){
            memset(u,0,sizeof(u));
            if(!match(i)) return false;
        }
        return true;
    }
    inline void init(){
        scanf("%d%d%d",&m,&n,&k);
        for(int i=1;i<=m;i++)
            for(int j=1;j<=n;j++)
                b[i][j]=true;
        for(int i=1,j,l;i<=k;i++){
            scanf("%d%d",&j,&l);
            b[l][j]=false;
        }
        for(int i=1;i<=m;i++)
            for(int j=!(i&1)+1;j<=n;j+=2)
                if(b[i][j]){
                    ++tot;
                    for(int l=1;l<D;l++)
                        if(b[i+x[l]][j+y[l]])
                            addedge(tot,(i+x[l]-1)*n+j+y[l]);
                }
        for(int i=1;i<=m;i++)
            for(int j=(i&1)+1;j<=n;j+=2)
                if(b[i][j]) sum++;
        if(sum==tot&&hungary()) printf("YES\n");
        else printf("NO\n");
    }
    int main(){
        freopen("chessboard.in","r",stdin);
        freopen("chessboard.out","w",stdout);
        init();
        fclose(stdin);
        fclose(stdout);
        return 0;
    }
  • 相关阅读:
    [转]编程能力与编程年龄
    github for windows 使用
    github 改位置
    Linux下设置和查看环境变量
    Docker基础 :网络配置详解
    docker入门实战笔记
    Jenkins +Maven+Tomcat+SVN +Apache项目持续集成构建
    使用nsenter工具进入Docker容器
    Docker从入门到实战(四)
    Docker从入门到实战(三)
  • 原文地址:https://www.cnblogs.com/AireenYe/p/poj2446.html
Copyright © 2020-2023  润新知