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;
}
posted @ 2021-07-11 10:04  acmloser  阅读(24)  评论(0编辑  收藏  举报