CH6801 棋盘覆盖

描述

给定一个N行N列的棋盘,已知某些格子禁止放置。求最多能往棋盘上放多少块的长度为2、宽度为1的骨牌,骨牌的边界与格线重合(骨牌占用两个格子),并且任意两张骨牌都不重叠。N≤100。

输入格式

第一行为n,t(表示有t个删除的格子)
第二行到t+1行为x,y,分别表示删除格子所在的位置
x为第x行,y为第y列,行列编号从1开始。 

输出格式

一个数,即最多能放的骨牌数

样例输入

8 0

样例输出

32
        </article>

题解

1要素:每个格子只能被一张骨牌覆盖
0要素:行号加列号的和奇偶性相同的格子之间没有边

所以满足二分图二要素,跑二分图匹配即可。

时间复杂度\(O(n^4)\)

co int N=100,dx[4]={0,0,1,-1},dy[4]={1,-1,0,0};
int n,m,ans,f[N*N];
bool b[N][N],v[N*N];
vector<int> e[N*N];
bool dfs(int x){
	for(unsigned i=0;i<e[x].size();++i){
		int y=e[x][i];
		if(v[y]) continue;
		v[y]=1;
		if(f[y]==-1||dfs(f[y])){
			f[y]=x;
			return 1;
		}
	}
	return 0;
}
int main(){
	read(n),read(m);
	while(m--) b[read<int>()-1][read<int>()-1]=1;
	for(int i=0;i<n;++i)for(int j=0;j<n;++j)if(!b[i][j])
		for(int k=0;k<4;++k){
			int x=i+dx[k],y=j+dy[k];
			if(0<=x&&x<n&&0<=y&&y<n&&!b[x][y])
				e[i*n+j].push_back(x*n+y),e[x*n+y].push_back(i*n+j);
		}
	memset(f,-1,sizeof f);
	for(int i=0;i<n;++i)for(int j=0;j<n;++j){
		if((i^j)&1) continue;
		memset(v,0,sizeof v);
		ans+=dfs(i*n+j);
	}
	printf("%d\n",ans);
	return 0;
}

posted on 2019-06-04 08:25  autoint  阅读(308)  评论(0)    收藏  举报

导航