棋盘覆盖

n*n的带有禁止位置的棋盘最多能放多少个1*2的多米诺骨牌

棋盘覆盖问题: 染色法
最多能放置多少个的问题
建模的策略在于找到问题包含的0要素和1要素

//确实只dfs左点
//match是双向的(对答案没有影响)
// 注意是vis[y]=1 因为注意到dfs访问的点都是左点 而y都是右点 我们要避免的是同一个右点被多次搜索

#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;

const int N=105;
int read()
{
	int x=0,f=0,c=getchar();
	while(c<'0'||c>'9'){if(c=='-')f=1;c=getchar();}
	while(c>='0'&&c<='9'){x=x*10+c-'0';c=getchar();}
	return f?-x:x;
}

struct Edge
{
	int to,next;
}e[10*N*N];
int head[N*N],cnt;
void _add(int a,int b){ e[++cnt]=(Edge){b,head[a]};head[a]=cnt;}
void add(int a,int b){_add(a,b); _add(b,a);}
bool mp[N][N];int n,T; 
int F(int x,int y){ return (x-1)*n+y;}
bool vis[N*N];
int match[N*N];

bool dfs(int x)
{
	for(int i=head[x];i;i=e[i].next)
	{
		int y=e[i].to;
		if(vis[y]) continue;
		vis[y]=1;
		if(!match[y] || dfs( match[y] )) { match[x]=y; match[y]=x; return true;}
	}
	return false;
}

int main()
{
	n=read(); T=read();
	for(int i=1;i<=T;i++) 
	{
		int x=read(),y=read();
		mp[x][y]=1;
	}
	for(int i=1;i<=n;i++)
		for(int j=1;j<n;j++) 
			if(!mp[i][j]&&!mp[i][j+1]) add( F(i,j),F(i,j+1) );
	for(int i=1;i<n;i++)
		for(int j=1;j<=n;j++)
			if(!mp[i][j]&&!mp[i+1][j]) add( F(i,j),F(i+1,j) );		
	int ans=0;
	for(int i=1;i<=n;i++)
		for(int j=1;j<=n;j++)
			if( ((i+j)&1)&&!mp[i][j]) 
			{
				memset(vis,0,sizeof vis);
				ans+=dfs(F(i,j));
			}
	printf("%d",ans);
	return 0;
			
}

可以造一般的数据 从一般数据的调试中找错误

二分图的增广路: 找到边(x,y)使匹配边和非匹配边交替出现

posted @ 2022-02-10 19:37  __iostream  阅读(44)  评论(0)    收藏  举报