您的位置:首页 > 其它

[POJ] 2446 Chessboard(二分图最大匹配)

2015-03-30 17:03 190 查看
题目地址:http://poj.org/problem?id=2446

本题建图是关键。因为卡片都是1*2,所以若点V被某个1*2卡片覆盖,则周围包含V的其它1*2区域都不成立。所以想到只要把V点划分在X集合,周围点在Y集合,V向周围点分别连边,就变成了二分图匹配问题,区分点V与周围点可以用横纵坐标之和的奇偶性。若棋盘上除障碍外都能被1*2卡片覆盖,则最大匹配数ans=(棋盘所有点数n*m-障碍数k)/2。本题在进行之前还有一个小优化,如果n*m-k是奇数,显而易见是不成立的,所以直接返回NO。

#include<cstdio>
#include<iostream>
#include<string.h>
#include<algorithm>
#include<math.h>
#include<stdbool.h>
#include<time.h>
#include<stdlib.h>
#include<set>
#include<map>
#include<stack>
#include<queue>
#include<vector>
using namespace std;
#define clr(x,y)    memset(x,y,sizeof(x))
#define sqr(x)      ((x)*(x))
#define rep(i,a,b)  for(int i=(a);i<=(b);i++)
#define LL          long long
#define INF         0x3f3f3f3f
#define A           first
#define B           second
#define PI          3.14159265358979323
const int N=2000+11;
const int dx[4]={0,0,1,-1};
const int dy[4]={1,-1,0,0};
int n,m,k1,k,k2,f
,g

,link
,flag

,a
,b
;

void init()
{
clr(f,0);
clr(g,0);
clr(flag,0);
clr(a,0);
clr(b,0);
clr(link,-1);
k1=0;
k2=0;
}

bool find(int x)
{
for(int i=0;i<k2;i++) {
if(!f[b[i]] && g[x][b[i]]) {
f[b[i]]=1;
if(link[b[i]]==-1 || find(link[b[i]])) {
link[b[i]]=x;
return true;
}
}
}

return false;
}

int hungary()
{
int ans=0;
for(int i=0;i<k1;i++) {
clr(f,0);
if(find(a[i])) ans++;
}
return ans;
}

int main()
{
int u,v,x,y;

init();
scanf("%d%d%d",&m,&n,&k);
if((m*n-k)&1) {
printf("NO\n");
return 0;
}
for(int i=1;i<=m;i++) {
for(int j=1;j<=n;j++)
flag[i][j]=1;
}
for(int i=1;i<=k;i++) {
scanf("%d%d",&y,&x);
flag[x][y]=0;
}

for(int i=1;i<=m;i++) {
for(int j=1;j<=n;j++) {

int p=(i-1)*n+j;
if((i+j)&1) {
if(flag[i][j]) a[k1++]=p;
}  else {
if(flag[i][j]) b[k2++]=p;
}
}
}

for(int i=1;i<=m;i++) {
for(int j=1;j<=n;j++) {
if(flag[i][j])
for(int k=0;k<4;k++) {
int nx=i+dx[k];
int ny=j+dy[k];
if(flag[nx][ny]) {
g[(i-1)*n+j][(nx-1)*n+ny]=1;
}
}
}
}

if(2*hungary()+k==n*m) printf("YES\n");
else  printf("NO\n");

return 0;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: