D172 二分图最大匹配 匈牙利算法 P5182 棋盘覆盖

D172 二分图最大匹配 匈牙利算法 P5182 棋盘覆盖_哔哩哔哩_bilibili

 

P5182 棋盘覆盖 - 洛谷

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

思路

格子 $(i,j)$ 的行列之和 $i+j$ 具有奇偶性,相邻格子一定奇偶性不同

我们把奇数格子看做黑格(男生),偶数格子看做白格(女生),格点分两类,转化为二分图最大匹配

枚举每个黑格,如果这个黑格没有被禁止,就让他向周围没有被禁止的白格连有向边(配对)

如果配对成功,说明这两个格子上可以放骨牌,答案加 1

上图中,带 “|” 的格子表示男生,每个男生向四周抓女生,先抓先得,但是可以让给后来的男生

如果每个男生按 “上右下左” 的顺序选女生,你可以模拟一下选让的过程

最多 $O(n^2)$ 个点,$O(n^2)$ 条边,所以时间复杂度 $O(n^4)$

参考:D25【模板】二分图最大匹配 匈牙利算法 - 董晓 - 博客园

 

// 二分图 匈牙利算法 O(V*E)
#include<bits/stdc++.h>
using namespace std;

const int N=110;
int n,m,g[N][N];
bool vis[N][N];
pair<int,int> match[N][N];
int dx[]={-1,0,1,0},dy[]={0,1,0,-1}; //上,右,下,左

bool dfs(int x,int y){
  for(int i=0; i<4; i++){ //四向扩展
    int a=x+dx[i],b=y+dy[i]; 
    if(a<1 || a>n || b<1 || b>n) continue; //出界
    if(g[a][b] || vis[a][b]) continue; //有禁格或已参与
    vis[a][b]=1; //标记参与这一轮试配
    auto [xx,yy]=match[a][b];
    if(xx==0 || dfs(xx,yy)){ //[xx,yy]没配对 或 可以让
      match[a][b]={x,y}; //记住配对
      return 1; //配对成功
    }
  }
  return 0; //配对失败
}
int main(){
  cin>>n>>m;
  for(int x,y;m--;)cin>>x>>y,g[x][y]=1; //禁格
  
  int ans=0;
  for(int i=1; i<=n; i++)
  for(int j=1; j<=n; j++)if((i+j)&1 && !g[i][j]){ //若是男生且可用
    memset(vis,0,sizeof vis);
    if(dfs(i,j)) ans++;
  }
  cout<<ans<<endl;
  // for(int i=1; i<=n; i++)
  // for(int j=1; j<=n; j++)if(!((i+j)&1))if(match[i][j].first)
  //   printf("(%d %d):(%d %d)\n",match[i][j].first,match[i][j].second,i,j);
}

 

posted @ 2026-05-26 17:36  董晓  阅读(24)  评论(0)    收藏  举报