当前位置: 代码迷 >> 综合 >> 匈牙利最大匹配 poj2446 Chessboard
  详细解决方案

匈牙利最大匹配 poj2446 Chessboard

热度:44   发布时间:2023-12-14 03:21:02.0

传送门:点击打开链接

题意:一个地图中,有一些障碍,然后有其他的空白位置,现在问是否能用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;
}