传送门
I think
同方格取数相同,是最大独立集问题.连边之后,找到一个割,此时与S和T仍然连接的点必然不在一个集合中,点的数量就是答案.要答案尽量大,于是就找出最小割即可.至于如何染色,应当从题给的图中得到启发。
Code
#include<cstdio>
#include<queue>
using namespace std;
const int sm = 4e4+10;
const int sn = 51e4;
const int Inf = 0x3f3f3f3f;
int N,K,S,T,tot=1;
int to[sn],hd[sm],nxt[sn],c[sn];
int cur[sm],lev[sm];
bool no[205][205];
struct node {
int x,y,g;
}now;
int xx[8] = {2,2,-2,-2,1,-1,1,-1};
int yy[8] = {1,-1,1,-1,2,2,-2,-2};
int Min(int x,int y) { return x<y?x:y; }
int Point(int x,int y) { return (x-1)*N+y; }
void Add(int u,int v,int w) {
to[++tot]=v,nxt[tot]=hd[u],hd[u]=tot,c[tot]=w;
to[++tot]=u,nxt[tot]=hd[v],hd[v]=tot,c[tot]=0;
}
bool chk(int x) { return x>=1&&x<=N; }
void Tag() {
for(int i=1;i<=N;++i)
for(int j=1;j<=N;++j) {
if(no[i][j]) continue;
if(i%2==j%2) {
Add(S,Point(i,j),1);
for(int k=0;k<8;++k)
if(chk(i+xx[k])&&chk(j+yy[k])&&!no[i+xx[k]][j+yy[k]])
Add(Point(i,j),Point(i+xx[k],j+yy[k]),Inf);
}
else Add(Point(i,j),T,1);
}
}
bool Bfs() {
for(int i=1;i<=T;++i)lev[i]=0;
queue<int>q; int t;
q.push(S),lev[S]=1;
while(!q.empty()) {
t=q.front(),q.pop();
for(int i=hd[t];i;i=nxt[i])
if(!lev[to[i]]&&c[i]>0) {
lev[to[i]]=lev[t]+1;
if(to[i]==T) return 1;
q.push(to[i]);
}
}
return 0;
}
int Dfs(int x,int mx) {
if(x==T||!mx) return mx;
int f;
for(int i=cur[x]?cur[x]:hd[x];i;i=nxt[i]) {
cur[x]=i;
if(lev[to[i]]==lev[x]+1&&c[i]>0)
if(f=Dfs(to[i],Min(mx,c[i])))
return c[i]-=f,c[i^1]+=f,f;
}
return 0;
}
void Dinic() {
int Flw=0,f;
while(Bfs()) {
for(int i=1;i<=T;++i)cur[i]=0;
while(f=Dfs(S,Inf)) Flw+=f;
}
printf("%d\n",N*N-K-Flw);
}
int main() {
int u,v;
scanf("%d%d",&N,&K);
S=N*N+1,T=S+1;
for(int i=1;i<=K;++i) {
scanf("%d%d",&u,&v);
no[u][v]=1;
}
Tag();
Dinic();
return 0;
}