匈牙利最大匹配 poj2446 Chessboard

传送门:点击打开链接

题意:一个地图中,有一些障碍,然后有其他的空白位置,现在问是否能用1*2的骨牌覆盖所有的空白位置,骨牌不能有重叠。

思路:乍看有点像状压dp,又有点像搜索,但是正解是二分图的最大匹配,而且做起来特别简单。

首先,我们枚举每一个空白的点,枚举四个方向,如果相邻的格子也为空白的,那么就在两个格子之间连一条边,很容易证明,这样的连线方法一定是二分图。

因为所有的格子,能通过(i+j)%2来分成两组,而这样连线刚好是两个点分别在其中的一组。

之后,我只要跑一遍二分图,看最大匹配*2是否刚好等于空格子的数量,就知道是否能完全覆盖了!

#include<map>
#include<set>
#include<cmath>
#include<ctime>
#include<stack>
#include<queue>
#include<cstdio>
#include<cctype>
#include<bitset>
#include<string>
#include<vector>
#include<cstring>
#include<iostream>
#include<algorithm>
#include<functional>
#define fuck(x) cout<<"["<<x<<"]"
#define FIN freopen("input.txt","r",stdin)
#define FOUT freopen("output.txt","w+",stdout)
//#pragma comment(linker, "/STACK:102400000,102400000")
using namespace std;
typedef long long LL;

const int MX = 3e3 + 5;
const int MS = 2e5 + 5;
int Head[MX], erear;
struct Edge {
    int v, nxt;
} E[MS];
void edge_init() {
    erear = 0;
    memset(Head, -1, sizeof(Head));
}
void edge_add(int u, int v) {
    E[erear].v = v;
    E[erear].nxt = Head[u];
    Head[u] = erear++;
}

int match[MX];
bool vis[MX];
bool DFS(int u) {
    for(int i = Head[u]; ~i; i = E[i].nxt) {
        int v = E[i].v;
        if(!vis[v]) {
            vis[v] = 1;
            if(match[v] == -1 || DFS(match[v])) {
                match[v] = u;
                return 1;
            }
        }
    }
    return 0;
}
int BM(int n) {
    int res = 0;
    memset(match, -1, sizeof(match));
    for(int u = 1; u <= n; u++) {
        memset(vis, 0, sizeof(vis));
        if(DFS(u)) res++;
    }
    return res;
}

int maz[100][100];
int dist[][2] = {{0, 1}, {0, -1}, {1, 0}, { -1, 0}};
int main() {
    int n, m, k; //FIN;
    while(~scanf("%d%d%d", &n, &m, &k)) {
        edge_init();
        memset(maz, 0, sizeof(maz));
        for(int i = 1; i <= k; i++) {
            int x, y;
            scanf("%d%d", &x, &y);
            maz[y][x] = 1;
        }

        for(int i = 1; i <= n; i++) {
            for(int j = 1; j <= m; j++) {
                if(maz[i][j]) continue;
                for(int k = 0; k < 4; k++) {
                    int nx = i + dist[k][0], ny = j + dist[k][1];
                    if(nx < 1 || nx > n || ny < 1 || ny > m || maz[nx][ny]) continue;
                    edge_add(i * m + j - m, nx * m + ny - m);
                    edge_add(nx * m + ny - m, i * m + j - m);
                }
            }
        }
        int sz = n * m - k;
        if(sz % 2 == 0 && BM(n * m) == sz) printf("YES\n");
        else printf("NO\n");
    }
    return 0;
}


你可能感兴趣的:(匈牙利最大匹配 poj2446 Chessboard)