这道题的思路其实还是让我很难受的
让我先从建图讲起
可以先像这样把图染个色
接着对于每个黑点,从源点建一条剩余流量为1的边
对于每个白点,到汇点建一条流量为1的边;
如果一个黑点可以跳到白点,就在图上连一条流量为inf的边
然后跑最小割就可以了
因为割掉这些边以后
代表着剩下的点已经不能够再互相到达了
割掉一条边代表着少一个点
所以最后用点的总数减去已经去掉了的点的数量,减去障碍数量
就是答案
附上代码
#include<bits/stdc++.h>
#pragma GCC optimize(2)
using namespace std;
const int inf=0x7fffffff;
int zou[8][2]={1,2,2,1,1,-2,-2,1,-1,2,-1,-2,-2,-1,2,-1};
int to[1000005],head[1000005],next[1000005],w[1000005];
int n,m,tot=1,a[205][205],s,t,depth[40005],shu1,shu2,hh[1000005];
queue <int> que;
void add(int x,int y,int z)
{
to[++tot]=y;
next[tot]=head[x];
head[x]=tot;
w[tot]=z;
}
void deal(int x,int y)
{
for(int i=0;i<=7;i++)
{
int xx=x+zou[i][0];
int yy=y+zou[i][1];
if(xx>=1&&xx<=n&&yy>=1&&yy<=n&&!a[xx][yy])
{
add((x-1)*n+y,(xx-1)*n+yy,inf);
add((xx-1)*n+yy,(x-1)*n+y,0);
}
}
}
bool bfs()
{
que.push(s);
memset(depth,0,sizeof(depth));
depth[s]=1;
while(!que.empty())
{
int x=que.front();
que.pop();
for(int i=head[x];i;i=next[i])
{
int y=to[i];
if(!depth[y]&&w[i])
{
depth[y]=depth[x]+1;
que.push(y);
}
}
}
if(depth[t]) return true;
return false;
}
int dinic(int x,int delta)
{
if(x==t)
return delta;
int rest=0;
for(int i=hh[x];i&δi=next[i])
if(depth[x]+1==depth[to[i]]&&w[i])
{
int y=to[i];
int ll=dinic(y,min(delta,w[i]));
w[i]-=ll;
w[i^1]+=ll;
delta-=ll;
rest+=ll;
hh[x]=i;
}
return rest;
}
int main()
{
cin>>n>>m;
s=n*n+1;
t=n*n+2;
for(int i=1;i<=m;i++)
{
scanf("%d%d",&shu1,&shu2);
a[shu1][shu2]=1;
}
for(int i=1;i<=n;i++)
{
for(int j=1;j<=n;j++)
{
if((i+j)%2&&!a[i][j])
{
add(s,(i-1)*n+j,1);
add((i-1)*n+j,s,0);
deal(i,j);
}
else if(!((i+j)%2)&&!a[i][j])
{
add((i-1)*n+j,t,1);
add(t,(i-1)*n+j,0);
}
}
}
int ans=0;
while(bfs())
{
for(int i=1;i<=n*n+2;i++)
hh[i]=head[i];
ans+=dinic(s,inf);
}
cout<<n*n-m-ans;
return 0;
}