[Non] 棋盘上的马

棋盘上的马

大意

给一个棋盘,和其上的不能放置的位置,求最多能放多少个互不攻击的马。

思路

首先,棋盘上约束的问题,可以考虑使用二分图最大匹配。

二分图的特性是二分的图,分成两半,这个题,由于马的走法,故每次跳到的地方的行列之和的奇偶性都不同。

于是按行列和的奇偶性去构造一个二分图,把不能跳的地方也用边建出来,于是问题就转换为求二分图最大点独立集。

代码

#include<iostream>
#include<vector>
#include<cstring>
using namespace std;

const int MAXN = 500;
bool vis[MAXN], vail[MAXN][MAXN];
int mac[MAXN], n, m;
vector<int> g[MAXN];
int dx[] = {1, 2, 2, 1, -1, -2, -2, -1};
int dy[] = {2, 1, -1, -2, -2, -1, 1, 2};

int id(int i, int j){
	return i * n + j;
}

bool dfs(int u){
	for(int &v : g[u]){
		if(!vis[v]){
			vis[v] = true;
			if(mac[v] == -1 || dfs(mac[v])){
				mac[v] = u;
				return true;
			}
		}
	}
	return false;
}

int hungary(int n){
	int cnt = 0;
	for(int i = 0;i < n;i ++){
        for(int j = 0;j < n;j ++){
            if(vail[i][j]) continue;
			memset(vis, 0, sizeof(vis));
			int pos = id(i, j);
			if((i + j) % 2){
				cnt += dfs(pos);
			}
		}
	}
	return cnt;
}

int main(){
	cin >> n >> m;
	memset(mac, -1, sizeof(mac));
	for(int i = 1;i <= m;i ++){
		int x, y; cin >> x >> y;
		vail[x - 1][y - 1] = 1;
	}
	for(int i = 0;i < n;i ++){
		for(int j = 0;j < n;j ++){
			int pos = id(i, j);
			if(vail[i][j]) continue;
			for(int k = 0;k < 8;k ++){
				int nx = i + dx[k];
				int ny = j + dy[k];
				if(nx < 0 || ny < 0 || nx >= n || ny >= n || vail[nx][ny]){
					continue;
				}
				g[pos].push_back(id(nx, ny));
			}
		}
	}
	cout << n * n - m - hungary(n) << '\n';
	return 0;
}
posted @ 2026-01-03 16:15  To_Carpe_Diem  阅读(5)  评论(0)    收藏  举报