AcWing 378. 骑士放置 题解

原题链接

题目描述

给定一个 N*M 的棋盘,有一些格子禁止放棋子。

问棋盘上最多能放多少个不能互相攻击的骑士(国际象棋的“骑士”,类似于中国象棋的“马”,按照“日”字攻击,但没有中国象棋“别马腿”的规则)。

样例

输入样例
2 3 0

输出样例
4

(二分图——最大独立集) O ( n ∗ m ) O(n*m) O(nm)

思路:通过涂色法(棋子位置和除棋子可到位置变黑色,其余不变)发现,黑色与白色有公共边,即可使用二分图求解

时间复杂度

O ( n ∗ m ) O(n*m) O(nm)

参考文献

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;
}
posted @ 2020-07-07 21:19  小罐猹  阅读(115)  评论(0编辑  收藏  举报