[POJ2446] Chessboard(二分图匹配)

传送门:Chessboard

题意为,在一块 m*n 的棋盘上,除去存在的若干个有障碍物的格子,判断该棋盘是否能被若干张 1*2(或 2*1)的卡片完全覆盖。

初看上去可能没什么想法,但是仔细观察就会发现,这些卡片覆盖的棋盘的坐标,都有一个相同的规律:覆盖的两个点,它们各自的横纵坐标之和,一个为奇一个为偶。利用这个规律,我们就可以将坐标和奇偶不同的格子分开,建立一个二分图,求能否完全覆盖棋盘的问题就自然变成了能否找到该二分图的完美匹配问题了。

本题的关键就是建图,而二分图匹配基本上算是模板,只需要注意:①输入中给的洞的坐标 (x, y),表示的是 y 行 x 列,也就是arr[y][x];②最后的条件判断,是 cnt != (m*n-k+1)/2,其中的 +1 表明除去不可行的格子外,若剩下的格子数为奇数,那么就一定没有解了,当然,提前判断也是可以的。

#include <iostream>
#include <vector>
#include <string.h>
#define ll long long
#define INF 0x3f3f3f3f
using namespace std;
const int maxn = 36;
const int maxnp = maxn*maxn;
int n, m, k;
vector<int> g[maxnp];
int type[maxn][maxn]; //记录格子的类型:洞、左图、右图
int match[maxnp], check[maxnp];

void read()
{
    cin >> m >> n >> k;
    int y, x;
    for(int i = 0; i < k; ++i)
    {
        cin >> x >> y;
        type[y][x] = -1; //这里x y的顺序是个坑
    }
}

void preSolve() //建立二分图
{
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
        {
            if((i+j)%2 && ~type[i][j])
            {
                type[i][j] = 1; //左图
                int cur = (i-1)*n+j-1, t;
                if(i != 1 && ~type[i-1][j])
                {
                    t = (i-2)*n+j-1;
                    g[cur].push_back(t);
                    g[t].push_back(cur);
                }
                if(i != m && ~type[i+1][j])
                {
                    t = i*n+j-1;
                    g[cur].push_back(t);
                    g[t].push_back(cur);
                }
                if(j != 1 && ~type[i][j-1])
                {
                    t = (i-1)*n+j-2;
                    g[cur].push_back(t);
                    g[t].push_back(cur);
                }
                if(j != n && ~type[i][j+1])
                {
                    t = (i-1)*n+j;
                    g[cur].push_back(t);
                    g[t].push_back(cur);
                }
            }
            else if(!((i+j)%2) && ~type[i][j])
            {
                type[i][j] = 2; //右图
            }
        }
}

bool dfs(int u)
{
    for(int i = 0; i < g[u].size(); ++i)
    {
        int v = g[u][i];
        if(!check[v])
        {
            check[v] = 1;
            if(match[v] == -1 || dfs(match[v]))
            {
                match[u] = v;
                match[v] = u;
                return 1;
            }
        }
    }
    return 0;
}

bool hungarian()
{
    for(int i = 0; i < maxnp; ++i)
        match[i] = -1;
    int cnt = 0;
    for(int i = 1; i <= m; ++i)
        for(int j = 1; j <= n; ++j)
            if(type[i][j] == 2 && match[(i-1)*n+j-1] == -1)
            {
                memset(check, 0, sizeof(check));
                if(dfs((i-1)*n+j-1))
                    ++cnt;
            }
    if(cnt != (m*n-k+1)/2) //!可能多出一个空格
        return 0;
    return 1;
}

void solve()
{
    preSolve();
    if(hungarian())
        cout << "YES" << endl;
    else
        cout << "NO" << endl;
}

int main()
{
    ios::sync_with_stdio(false);
    cin.tie(0); cout.tie(0);
    read();
    solve();
    return 0;
}

猜你喜欢

转载自blog.csdn.net/HNUCSEE_LJK/article/details/100082763