P3355 骑士共存问题
题目描述
在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入
对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击
输入输出格式
输入格式:
第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。
输入样例#1: 复制
3 2 1 1 3 3
输出样例#1: 复制
5
建图:整个棋盘可以分为黑白两种颜色(坐标相加奇偶性)。显然是让求二分图最大独立集。在二分图的基础上,相互攻击到的可以连边即可!lyd大佬说了 二分图用dinic跑比较快~ 那就走起~~
using namespace std;
#define rep(i,a,n) for (int i=a;i<n;i++)
#define per(i,a,n) for (int i=n-1;i>=a;i--)
#define oo cout<<"!!!"<<endl;
typedef long long ll;
typedef unsigned long long ull;
#define ms(s) memset(s, 0, sizeof(s))
const int inf = 0x3f3f3f3f;
//head
const int maxn = 1e6+11;
int head[maxn],ver[maxn],edge[maxn],nxt[maxn],d[maxn],tot;
int n,m,s,t,maxflow;
void add(int x,int y,int z)
{
ver[++tot] = y;edge[tot] = z;nxt[tot] = head[x],head[x] = tot;
ver[++tot] = x;edge[tot] = 0;nxt[tot] = head[y],head[y] = tot;
}
bool bfs()
{
ms(d);
queue<int>q;
q.push(s);
d[s] = 1;
while(!q.empty())
{
int x = q.front();q.pop();
for(int i = head[x];i;i = nxt[i])
{
if(edge[i] && !d[ver[i]])
{
q.push(ver[i]);
d[ver[i]] = d[x] + 1;
if(ver[i] == t)return 1;
}
}
}
return 0;
}
int dinic(int x,int flow)
{
if(x == t)return flow;
int rest = flow,k;
for(int i = head[x];i && rest;i = nxt[i])
{
if(edge[i] && d[ver[i]] == d[x]+1)
{
k = dinic(ver[i],min(rest,edge[i]));
if(!k)d[ver[i]] = 0;
edge[i] -= k;
edge[i^1] +=k;
rest -= k;
}
}
return flow - rest;
}
int dx[] = {1,1,2,2,-1,-1,-2,-2},dy[] = {-2,2,1,-1,2,-2,1,-1};
bool mp[222][222];
inline int id(int x,int y){return (x-1)*n + y;}
int main()
{
cin>>n>>m;
int sum = n*n-m;
t = n*n + 2;
s = 0;
tot = 1;
while(m--)
{
int x,y;
scanf("%d%d",&x,&y);mp[x][y] =1;
}
rep(i,1,n+1)
rep(j,1,n+1)
{
if(mp[i][j])continue;
if((i+j)&1)
{
add(s,id(i,j),1);
rep(k,0,8)
{
int x = i + dx[k],y = j + dy[k];
if(x < 1 || y < 1 || x > n || y >n || mp[x][y])continue;
add(id(i,j),id(x,y),inf);
}
}
else add(id(i,j),t,1);
}
int flow = 0;
while(bfs())
while(flow = dinic(s,inf)) maxflow += flow;
cout << sum - maxflow << endl;
return 0;
}