POJ_2446_Chessboard(二分图婚配)

POJ_2446_Chessboard(二分图匹配)
Chessboard
Time Limit: 2000MS   Memory Limit: 65536K
Total Submissions: 14479   Accepted: 4501

Description

Alice and Bob often play games on chessboard. One day, Alice draws a board with size M * N. She wants Bob to use a lot of cards with size 1 * 2 to cover the board. However, she thinks it too easy to bob, so she makes some holes on the board (as shown in the figure below).
POJ_2446_Chessboard(二分图婚配)

We call a grid, which doesn’t contain a hole, a normal grid. Bob has to follow the rules below:
1. Any normal grid should be covered with exactly one card.
2. One card should cover exactly 2 normal adjacent grids.

Some examples are given in the figures below:
POJ_2446_Chessboard(二分图婚配)
A VALID solution.

POJ_2446_Chessboard(二分图婚配)
An invalid solution, because the hole of red color is covered with a card.

POJ_2446_Chessboard(二分图婚配)
An invalid solution, because there exists a grid, which is not covered.

Your task is to help Bob to decide whether or not the chessboard can be covered according to the rules above.

Input

There are 3 integers in the first line: m, n, k (0 < m, n <= 32, 0 <= K < m * n), the number of rows, column and holes. In the next k lines, there is a pair of integers (x, y) in each line, which represents a hole in the y-th row, the x-th column.

Output

If the board can be covered, output "YES". Otherwise, output "NO".

Sample Input

4 3 2
2 1
3 3

Sample Output

YES

Hint

POJ_2446_Chessboard(二分图婚配)
A possible solution for the sample input.


题意:给出一个矩形N*M棋盘,有K个格子是空洞,然后用2*1的矩形,对所有非空洞的格子进行覆盖,问能否完全覆盖。

分析:二分图匹配问题。关键问题是如何建图,我们可以把每两个相邻的非空格子用一条边连接起来,这样的话相当于这两个格子处于分别处于两个集合当中,这样的话两个相邻的格子就不会处于同一个集合当中。然后这样子连边就构成了一个二分图了。然后求出最大匹配数。如果匹配数 + k = N*M,输出“YES”。

题目链接:http://poj.org/problem?id=2446

代码清单:

#include<map>
#include<queue>
#include<cmath>
#include<stack>
#include<ctime>
#include<cctype>
#include<string>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
typedef long long ll;
const int maxn = 32 + 5;
const int maxv = 2000 + 5;

int m,n,k;
int x,y,cnt;

int match[maxv];
bool vis[maxv];
int num[maxn][maxn];
bool hole[maxn][maxn];
bool graph[maxv][maxv];

bool dfs(int u){         //匈牙利算法
    for(int v=1;v<=cnt;v++){
        if(!vis[v]&&graph[u][v]){
            vis[v]=true;
            if(match[v]==-1 || dfs(match[v])){
                match[v]=u;
                return true;
            }
        }
    }return false;
}

bool ok(){
    int ans=0;
    for(int i=1;i<=cnt;i++){
        memset(vis,false,sizeof(vis));
        if(dfs(i)) ans++;
    }
    if(ans==cnt) return true;
    return false;
}

int main(){
    scanf("%d%d%d",&m,&n,&k);
    memset(match,-1,sizeof(match));
    memset(hole,false,sizeof(hole));
    memset(graph,false,sizeof(graph));
    for(int i=0;i<k;i++){
        scanf("%d%d",&x,&y);
        hole[y-1][x-1]=true;
    }
    if((n*m-k)&1) printf("NO\n"); //奇偶性剪枝

    else{
        cnt=0;
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!hole[i][j])
                    num[i][j]=++cnt;
            }
        }

        //建立二分图
        for(int i=0;i<m;i++){
            for(int j=0;j<n;j++){
                if(!hole[i][j]){  
                    if(i-1>=0&&!hole[i-1][j]) graph[num[i][j]][num[i-1][j]]=true;
                    if(i+1<m&&!hole[i+1][j]) graph[num[i][j]][num[i+1][j]]=true;
                    if(j-1>=0&&!hole[i][j-1]) graph[num[i][j]][num[i][j-1]]=true;
                    if(j+1<n&&!hole[i][j+1]) graph[num[i][j]][num[i][j+1]]=true;
                }
            }
        }

        if(ok()) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}