棋盘覆盖
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)使匹配边和非匹配边交替出现

浙公网安备 33010602011771号