ch6091 骑士放置(二分图最大独立集)
题目链接 https://www.acwing.com/problem/content/380/
思路:
让求最多可以放多少个互相之间不攻击的骑士。可以这样考虑,将图中可以互相攻击的点连边,会得到一个图,而且是一个二分图。如果分不清哪些是左部节点哪些是右部节点,可以采用染色法对其进行分别。现在要求的是一个最大的集合满足集合中任意两点之间没有连线,即最大独立集。最大独立集 = 二分图中的点的总数 - 最大匹配。本题中,二分图中的点的总数也可以用染色法中被染色的点数表示,更简单的表示就是,一共n*m个点,其中又t个点被禁止放置了,那么这t个点就不会出现在二分图中,所以总点数是n*m-t,然后建图求最大匹配即可。
/**
* Author: correct
*/
#include <bits/stdc++.h>
using namespace std;
#define mem(a, b) memset(a, b, sizeof a)
const int N = 1e5;
int head[N], nex[N], to[N], cnt;
int n, m, t;
int color[110][110];
int dx[] = {2, 2, -2, -2, 1, 1, -1, -1};
int dy[] = {1, -1, 1, -1, 2, -2, 2, -2};
int match[N];
bool w[110][110];
bool vis[N];
void pre_work(){
mem(head, -1);
mem(nex, -1);
cnt = 0;
mem(color, 0);
mem(match, -1);
mem(w, true);
}
void add(int a, int b){
++cnt;
to[cnt] = b;
nex[cnt] = head[a];
head[a] = cnt;
}
int get(int x, int y){
return (x - 1) * 1000 + y;
}
bool check(int xx, int yy){
if (xx >= 1 && xx <= n && yy >= 1 && yy <= m && w[xx][yy])return 1;
return 0;
}
void build(){
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
for (int k = 0; k <= 7; k++){
int xx = i + dx[k];
int yy = j + dy[k];
if (check(xx, yy)){
add(get(i, j), get(xx, yy));
}
}
}
}
}
int getX(int x){
return x / 1000 + 1;
}
int getY(int x){
return x % 1000;
}
bool colors(int x, int c){
int xx, yy;
yy = x % 1000;
xx = x / 1000 + 1;
color[xx][yy] = c;
for (int i = head[x]; ~i; i = nex[i]){
int y = to[i];
if (!color[getX(y)][getY(y)]){
colors(y, 3 - c);
}
else if(color[getX(y)][getY(y)] == c){
return 0;
}
}
return 1;
}
bool dfs(int x){
for (int i = head[x]; ~i; i = nex[i]){
int y = to[i];
if (vis[y])continue;
vis[y] = 1;
if (match[y] == -1 || dfs(match[y])){
match[y] = x;
return 1;
}
}
return 0;
}
int solve(){
build();
int ans = n * m - t;
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (!color[i][j])colors(get(i, j), 1);
}
}
for (int i = 1; i <= n; i++){
for (int j = 1; j <= m; j++){
if (color[i][j] == 1 && w[i][j]){
mem(vis, 0);
if (dfs(get(i, j)))ans--;
}
}
}
return ans;
}
int main()
{
pre_work();
scanf("%d %d %d", &n, &m, &t);
for (int i = 0; i < t; i++){
int x, y;
scanf("%d %d", &x, &y);
w[x][y] = 0;
}
printf("%d\n", solve());
return 0;
}
本文来自博客园,作者:correct,转载请注明原文链接:https://www.cnblogs.com/correct/p/12861924.html

浙公网安备 33010602011771号