Link
Solve
对棋盘进行染色,黑白节点分别作为二分图的左右部节点。
对于一个在白色节点的马来说,一定在一步之内不能跳到另外一个白色节点
则通过"日"在相对应的节点之间建边
求上述二分图的的最大独立子集就是答案
Code
#include <cstdio>
#include <iostream>
#include <cstring>
#include <vector>
using namespace std;
const int MAXN = 1000000;
const int nxt_x[8]={-1,-2,-2,-1,1,2,2,1};
const int nxt_y[8]={-2,-1,1,2,2,1,-1,-2};
int n,m,cnt,ans;
bool Map[2001][2001];
bool used[100001];
int match[100001],head[MAXN];
vector<int> node;
struct Edge
{
int next,to;
}e[MAXN];
inline void add(int u,int v)
{
cnt++;
e[cnt].to=v;
e[cnt].next=head[u];
head[u]=cnt;
}
bool Find(int u)
{
for(int i=head[u];i;i=e[i].next)
{
int v=e[i].to;
if(!used[v])
{
used[v]=1;
if(match[v]==-1 || Find(match[v]))
{
match[v]=u;
return 1;
}
}
}
return 0;
}
int main()
{
freopen("P3355.in","r",stdin);
freopen("P3355.out","w",stdout);
cin>>n>>m;
for(int i=1;i<=m;i++)
{
int x,y;
cin>>x>>y;
Map[x][y]=1;
}
for(int x=1;x<=n;x++)
for(int y=1;y<=n;y++)
if(!Map[x][y] && (x+y)%2)
{
node.push_back(n*(x-1)+y);
for(int i=0;i<8;i++)
{
int to_x=x+nxt_x[i];
int to_y=y+nxt_y[i];
if(to_x<1 || to_x>n || to_y<1 || to_y>n) continue;
if(!Map[to_x][to_y])
add(n*(x-1)+y,n*(to_x-1)+to_y);
}
}
memset(match,-1,sizeof(match));
for(int i=0;i<node.size();i++)
{
memset(used,0,sizeof(used));
ans+=Find(node[i]);
}
cout<<n*n-m-ans;
return 0;
}