D180 二分图最大独立集 匈牙利算法 P10939 骑士放置

D180 二分图最大独立集 匈牙利算法 P10939 骑士放置_哔哩哔哩_bilibili

 

P3355 骑士共存问题 - 洛谷          P10939 骑士放置 - 洛谷

有一个 𝑛×𝑛 的国际象棋棋盘,其中一些位置不能放棋子,问最多可以放多少个马使得这些马不会互相攻击。

image

思路

日字对角的坐标之和的奇偶性不同,按照格点的奇偶性染色,满足二分图的性质

奇格点的马只能攻击周围 8 个方向日字对角的偶格点的马,偶格点的马同理

把奇格点作为左部点,偶格点作为右部点,建立二分图,能攻击到就连边

目标是找出最多的点互相攻击不到,即找出最多的点,使点之间没有边,即最大独立集。图中最大独立集为 5 个

答案 $=\;n*n\;-$ 禁止放置格数 $-$ 最大匹配数

奇格点数为 $O(N^2)$,连边总数为 $O(N^2)$,时间复杂度为 $O(N^4)$,匈牙利算法依赖数据和搜索次序

参考:D179 二分图最大独立集 匈牙利算法 CF1404E Bricks - 董晓 - 博客园

 

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

const int N=210,M=20010;
int n,m,cnt,c1,c2,f[N][N],g[N][N];
int px[M],py[M],match[M];
bitset<M> vis;
const int dx[8]={1,1,-1,-1,2,2,-2,-2};
const int dy[8]={-2,2,-2,2,-1,1,-1,1};
// const int dx[8]={-2,-1,1,2,2,1,-1,-2};
// const int dy[8]={1,2,2,1,-1,-2,-2,-1}; //TLE 1个点

bool dfs(int u){
  for(int i=0; i<8; i++){ //8向搜索
    int a=px[u]+dx[i], b=py[u]+dy[i];
    if(a<1||b<1||a>n||b>n) continue; //越界
    int v=g[a][b]; //女生v
    if(vis[v] || f[a][b]) continue; //已参与或障碍
    vis[v]=1;
    if(!match[v]||dfs(match[v])){ //v没配对或其男友可退让
      match[v]=u;
      return 1; //配对成功
    }
  }
  return 0; //配对失败
}
int main(){
  ios::sync_with_stdio(0);cin.tie(0);cout.tie(0);
  cin>>n>>m;
  for(int i=0,x,y; i<m; i++)cin>>x>>y,f[x][y]=1; //障碍格点
  for(int i=1; i<=n; i++)for(int j=1; j<=n; j++)if(!f[i][j]){
    if((i+j)&1){
      g[i][j]=++c1; //奇格点编号
      px[c1]=i; py[c1]=j; //编号的坐标  
    }
    else g[i][j]=++c2; //偶格点编号
  }
  
  for(int i=1; i<=c1; i++){ //枚举奇格点编号
    vis=0;
    cnt+=dfs(i);
  }
  cout<<n*n-m-cnt;
}

 

posted @ 2026-05-31 19:02  董晓  阅读(25)  评论(0)    收藏  举报