[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;
}
原文地址:https://www.cnblogs.com/AireenYe/p/poj2446.html