AcWing 372. 棋盘覆盖
原题链接
考察:二分匹配
思路:
长度为2的骨牌,相当于骨牌所占用两个点匹配,不重叠:没有一个点共用两条边,求能放的骨牌:最大匹配数.
二分匹配前一定要先判断二分图,再将点分成两派,只枚举其中一派.
Code
#include <iostream>
#include <cstring>
using namespace std;
const int N = 110;
int n,T,idx,h[N*N],match[N*N];
int xx[4] = {-1,1,0,0},yy[4] = {0,0,-1,1};
bool vis[N][N],st[N*N];
struct Road{
int to,ne;
}road[N*N<<2];//求二分图匹配一定需要将点划分为两边
void add(int a,int b)
{
road[idx].to = b,road[idx].ne = h[a],h[a] = idx++;
}
int find(int u)
{
for(int i=h[u];~i;i=road[i].ne)
{
int v = road[i].to;
if(st[v]) continue;
st[v] = 1;
if(!match[v]||find(match[v]))
{
match[v] = u;
return 1;
}
}
return 0;
}
int main()
{
// freopen("in.txt","r",stdin);
scanf("%d%d",&n,&T);
memset(h,-1,sizeof h);
while(T--)
{
int x,y;
scanf("%d%d",&x,&y);
vis[x][y] = 1;
}
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
for(int i=0;i<4;i++)
{
if(vis[x][y]||((x+y)&1)) break;
int dx = x+xx[i],dy = y+yy[i];
if(dx>0&&dx<=n&&dy>0&&dy<=n&&!vis[dx][dy])
{
int a = (x-1)*n+y;
int b = (dx-1)*n+dy;
add(a,b);
}
}
int res = 0;
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
if(!vis[i][j]&&(i+j)%2==0)//存在点递归绑定正在绑的
{
int s = (i-1)*n+j;
memset(st,0,sizeof st);
if(match[s]) continue;
if(find(s)) res++;
}
printf("%d\n",res);
return 0;
}