D172 二分图最大匹配 匈牙利算法 P5182 棋盘覆盖
D172 二分图最大匹配 匈牙利算法 P5182 棋盘覆盖_哔哩哔哩_bilibili
给定一个 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); }
浙公网安备 33010602011771号