您的位置:首页 > 其它

poj 2446 Chessboard 二分图的最大匹配

2014-10-18 13:31 375 查看
题意:

给一个n*m的棋盘,上面有k个点被挖掉,问是否能用1*2的片段把剩下的棋盘恰好完全覆盖。

思路:

把剩下的顶点编号,若两个顶点可以被一个片段覆盖则他们之间有一条边,则转化为求二分图的最大匹配问题,若匹配数M+k==n*m则可以完全覆盖,否则不行。

代码:

poj 2446 by sepNINE
#include<iostream>
using namespace std;
int chessboard[36][36];
const int maxN=1200;
bool g[maxN][maxN];
bool vis[maxN];
int link[maxN];
int dirr[4]={0,0,-1,1};
int dirc[4]={-1,1,0,0};
int v1,v2,M;

bool dfs(int x)
{
	for(int y=1;y<=v2;++y)	
		if(g[x][y]&&!vis[y]){
			vis[y]=true;
			if(link[y]==0||dfs(link[y])){
				link[y]=x;
				return true;
			}
		}
	return false;
}

void hungary()
{
	for(int x=1;x<=v1;++x){
		memset(vis,false,sizeof(vis));
		if(dfs(x))
			++M;
	}	
	return ;
}

int main()
{
	int i,j,n,m,k,cnt;
	scanf("%d%d%d",&n,&m,&k);
	memset(chessboard,0,sizeof(chessboard));
	memset(g,false,sizeof(g));
	memset(link,0,sizeof(link));
	int x,y;
	for(i=0;i<k;++i){
		scanf("%d%d",&x,&y);
		chessboard[y][x]=-1;
	}
	
	cnt=0;
	for(i=1;i<=n;++i)
		for(j=1;j<=m;++j)
			if(chessboard[i][j]!=-1)
				chessboard[i][j]=++cnt;
	
	for(i=1;i<=n;++i)
		for(j=1;j<=m;++j)
			if(chessboard[i][j]>0)
			for(int p=0;p<4;++p){
				int newi=i+dirr[p];
				int newj=j+dirc[p];
				if(newi>=1&&newi<=n&&newj>=1&&newj<=m&&chessboard[newi][newj]>0){
					g[ chessboard[i][j] ][ chessboard[newi][newj] ]=1;
					g[ chessboard[newi][newj] ][ chessboard[i][j] ]=1;
				}
			}
	
	v1=v2=cnt;
	M=0;
	hungary();
	if(M+k==n*m)		
		printf("YES");
	else
		printf("NO");		 
	return 0;	
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: