原题链接
题目描述
给定一个 N*M 的棋盘,有一些格子禁止放棋子。
问棋盘上最多能放多少个不能互相攻击的骑士(国际象棋的“骑士”,类似于中国象棋的“马”,按照“日”字攻击,但没有中国象棋“别马腿”的规则)。
样例
输入样例
2 3 0
输出样例
4
(二分图——最大独立集) O ( n ∗ m ) O(n*m) O(n∗m)
思路:通过涂色法(棋子位置和除棋子可到位置变黑色,其余不变)发现,黑色与白色有公共边,即可使用二分图求解
时间复杂度
O ( n ∗ m ) O(n*m) O(n∗m)
参考文献
y总的课+《算法竞赛进阶指南》
C++ 代码
#include<bits/stdc++.h>
#define x first
#define y second
using namespace std;
typedef pair<int,int> PII;
const int maxn=110;
PII match[maxn][maxn];
bool g[maxn][maxn];
int n,m,t,x,y,res;
bool st[maxn][maxn];
int fx[]={-2,-1,1,2,2,1,-1,-2};
int fy[]={1,2,2,1,-1,-2,-2,-1};
bool find(int x,int y){
for(int i=0;i<8;i++){
int a=x+fx[i];
int b=y+fy[i];
if(a<1||a>n||b<1||b>m)continue;
if(g[a][b]||st[a][b])continue;
st[a][b]=true;
PII t=match[a][b];
if(t.x==0||find(t.x,t.y)){
match[a][b]={x,y};
return true;
}
}
return false;
}
int main(){
scanf("%d%d%d",&n,&m,&t);
for(int i=1;i<=t;i++){
scanf("%d%d",&x,&y);
g[x][y]=true;
}
for(int i=1;i<=n;i++){
for(int j=1;j<=m;j++){
if((i+j)%2||g[i][j])continue;
memset(st,false,sizeof st);
if(find(i,j)){
res++;
}
}
}
cout<<n*m-res-t;
return 0;
}