最大独立集:在一个图中,选出最多的点,使得选出的点之间没有边。
最大团:在一个图中,选出最多的点,使得任意两点之间有边。
两者互补(补图:在一个图中,如果原来两点之间有边,则去掉该边,如果两点之间无边,则加上该边)
在二分图中,求最大独立集<=>求去掉最少的点将所有边破坏<=>找最小点覆盖<=>最大匹配
结论:设总点数是n,最大匹配是m,最大独立集是n-m
该题中,将每个格子看成点,如果两个格子中放棋子之后可以攻击到则连一条边,任务就是找出最多的点互相攻击不到,既找出最多的点,使点之间没有边,即最大独立集问题,这里同样按照点的奇偶性染色,可以发现同样满足二分图的性质,所以最后的结果就是n*m-禁止放置点数-最大匹配数。
#include <iostream>
#include <cstring>
#define x first
#define y second
using namespace std;
const int N = 110;
typedef pair<int , int> PII;
PII match[N][N];
int n , m , k;
bool st[N][N] , g[N][N];
int dx[8] = {-1 , -2 , -2 , -1 , 1 , 2 , 2 , 1} , dy[8] = {-2 , -1 , 1 , 2 , 2 , 1 , -1 , -2};//延伸出去的8个方向
bool find(int x , int y)
{
for(int i = 0 ; i < 8 ; i++)
{
int a = x + dx[i] , b = y + dy[i];
if(a >= 1 && b >= 1 && a <= n && b <= m && !g[a][b] && !st[a][b])
{
st[a][b] = true;
PII t = match[a][b];
if(!t.x || find(t.x , t.y))
{
match[a][b] = {x , y};
return true;
}
}
}
return false;
}
int main()
{
cin >> n >> m >> k;
for(int i = 0 ; i < k ; i++)
{
int a , b;
cin >> a >> b;
g[a][b] = true;
}
int res = 0;
for(int i = 1 ; i <= n ; i++)
for(int j = 1 ; j <= m ; j++)
if((i + j) % 2 == 1 && !g[i][j])
{
memset(st , 0 , sizeof st);
if(find(i , j)) res++;
}
cout << n * m - res - k << endl;
return 0;
}