最小割 用割来表示互斥的关系
我们可以发现一个性质 就是马只能由黑格跳到白格
那么我们对图进行黑白染色(第一次写还写错了)
然后黑色点向能到达的白色点连边 障碍不进行建图
那么最后的答案就是n-m再减去最小割
#include <cstdio>
#include <algorithm>
#include <cstring>
using namespace std;
const int N=205*3,M=10*N*N,S=N*N-1,T=N*N-2,INF=1e9,DX[]={1,1,2,2,-1,-1,-2,-2},DY[]={2,-2,1,-1,2,-2,1,-1};
int n=0,m=0;
int b[N][N],color[N][N];
int head[N*N],to[M],next[M],c[M],f[M],edge=0;
int q[M],front=0,back=0,d[N*N];
inline void addEdge(int u,int v,int ac) {
to[edge]=v,c[edge]=ac,next[edge]=head[u],head[u]=edge++;
to[edge]=u,c[edge]=0,next[edge]=head[v],head[v]=edge++;
}
inline int num(int i,int j) {
return j+n*(i-1);
}
#define X i+DX[k]
#define Y j+DY[k]
inline void build() {
memset(head,-1,sizeof(head));
int c0=0;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
color[i][j]=(i+j)%2;
for (int i=1;i<=n;++i)
for (int j=1;j<=n;++j)
if (!b[i][j]) {
int x=num(i,j);
color[i][j]?addEdge(S,x,1):addEdge(x,T,1);
if (color[i][j])
for (int k=0;k<8;++k)
if (X>=1 && Y>=1 && X<=n && Y<=n && !b[X][Y])
addEdge(x,num(X,Y),INF);
}
}
#undef X
#undef Y
inline int bfs() {
front=back=0;
memset(d,-1,sizeof(d));
q[back++]=S;
d[S]=0;
while (front<back) {
int x=q[front++];
for (int e=head[x];~e;e=next[e]) {
int v=to[e];
if (d[v]==-1 && c[e]>f[e]) {
d[v]=d[x]+1;
q[back++]=v;
}
}
}
return d[T]!=-1;
}
int dfs(int x,int mn) {
if (x==T || !mn)
return mn;
int flow=0;
for (int e=head[x];~e;e=next[e]) {
int v=to[e];
if (d[v]==d[x]+1 && c[e]>f[e]) {
int f0=dfs(v,min(mn,c[e]-f[e]));
flow+=f0;
mn-=f0;
f[e]+=f0;
f[e^1]-=f0;
if (!mn)
return flow;
}
}
if (mn)
d[x]=-1;
return flow;
}
inline int dinic() {
int flow=0;
while (bfs())
flow+=dfs(S,INF);
return flow;
}
int main(void) {
freopen("knight.in","r",stdin);
freopen("knight.out","w",stdout);
scanf("%d%d",&n,&m);
for (int i=1;i<=m;++i) {
int x=0,y=0;
scanf("%d%d",&x,&y);
b[x][y]=1;
}
build();
printf("%d\n",n*n-m-dinic());
fclose(stdin);
fclose(stdout);
return 0;
}
好菜啊 模板有个地方写错了 还是学长davidxu帮我发现的 QAQQQQ