LibreOJ 6226. 「網路流 24 題」騎士共存問題
阿新 • • 發佈:2021-02-20
技術標籤:圖論 —— 二分圖最大匹配、二分圖多重匹配、二分圖最大權匹配
連結
題意
在一個 n ∗ n n*n n∗n 個方格的國際象棋棋盤上,馬(騎士)可以攻擊的棋盤方格如圖所示。棋盤上某些方格設定了障礙,騎士不得進入。
對於給定的 n ∗ n n*n n∗n 個方格的國際象棋棋盤和障礙標誌,計算棋盤上最多可以放置多少個騎士,使得它們彼此互不攻擊。
思路
二分圖最大獨立集
模擬一下可以發現棋盤可以根據行列和的奇偶性染色
求出最大匹配,二分圖最大獨立集 = 點數 - 最大匹配
程式碼
#include <bits/stdc++.h>
#define SZ(x) (int)(x).size()
#define ALL(x) (x).begin(),(x).end()
#define PB push_back
#define EB emplace_back
#define MP make_pair
#define FI first
#define SE second
using namespace std;
typedef double DB;
typedef long double LD;
typedef long long LL;
typedef unsigned long long ULL;
typedef pair<int,int > PII;
typedef vector<int> VI;
typedef vector<PII> VPII;
//head
const int DIR[8][2]={-1,-2,-2,-1,-2,1,-1,2,1,2,2,1,2,-1,1,-2};
const int N=205;
bool vis[N][N];
int n,m,match[N*N],dep[N*N];
VI p;
bool bfs() {
queue<int> q;
for(int i=0;i<n*n;i++) dep[i]=0;
for(auto x:p) if( !vis[x/n][x%n]&&match[x]==-1) dep[x]=1,q.push(x);
bool f=false;
while(SZ(q)) {
int u=q.front();
q.pop();
int x=u/n,y=u%n;
for(int i=0;i<8;i++) {
int tx=x+DIR[i][0],ty=y+DIR[i][1];
if(tx<0||tx>=n||ty<0||ty>=n||vis[tx][ty]) continue;
int v=tx*n+ty;
if(dep[v]) continue;
dep[v]=dep[u]+1;
if(match[v]==-1) f=true;
else dep[match[v]]=dep[v]+1,q.push(match[v]);
}
}
return f;
}
bool dfs(int u) {
int x=u/n,y=u%n;
for(int i=0;i<8;i++) {
int tx=x+DIR[i][0],ty=y+DIR[i][1];
if(tx<0||tx>=n||ty<0||ty>=n||vis[tx][ty]) continue;
int v=tx*n+ty;
if(dep[v]!=dep[u]+1) continue;
dep[v]=0;
if(match[v]==-1||dfs(match[v])) {
match[v]=u;
match[u]=v;
return true;
}
}
return false;
}
int HK() {
for(int i=0;i<n*n;i++) match[i]=-1;
int res=0;
while(bfs()) for(auto x:p) if(!vis[x/n][x%n]&&match[x]==-1&&dfs(x)) res++;
return res;
}
int main() {
ios::sync_with_stdio(false);
cin.tie(nullptr);
cin>>n>>m;
for(int i=1;i<=m;i++) {
int x,y;
cin>>x>>y;
vis[x-1][y-1]=true;
}
for(int i=0;i<n*n;i++) if((i/n+i%n)&1&&!vis[i/n][i%n]) p.PB(i);
cout<<n*n-m-HK()<<'\n';
return 0;
}