AW378 骑士放置

题目地址


易错点:

  • 八倍开边,我真的没有开挂.
  • 只有坐标不越界的点集才是好同志.
  • 支持相互match这个一定要好评.

#include<cstdio>
#include<iostream>
#include<cstring>
using namespace std;
const int MAXN=120*120;
int dx[8]={-2,-2,-1,-1,1,1,2,2},dy[8]={1,-1,2,-2,2,-2,1,-1};
struct Edge{
	int from,to,nxt;
}e[MAXN*8];
int head[MAXN],edgeCnt=1;
void addEdge(int u,int v){
	e[++edgeCnt].from=u;
	e[edgeCnt].to=v;
	e[edgeCnt].nxt=head[u];
	head[u]=edgeCnt;
}
int vis[MAXN],match[MAXN];
bool dfs(int x){
	for(int i=head[x];i;i=e[i].nxt){
		int nowV=e[i].to;
		if(vis[nowV])continue;
		vis[nowV]=1;
		if(!match[nowV]||dfs(match[nowV])){
			match[nowV]=x;
			match[x]=nowV;
			return 1;
		}
	}
	return 0;
}
int m;
int getHash(int i,int j){
	return (i-1)*m+j;
}
int a[120][120];
int main(){
	int n,t;
	scanf("%d%d%d",&n,&m,&t);
	for(int i=1;i<=t;i++){
		int x,y;
		scanf("%d%d",&x,&y);
		a[x][y]=1;
	}
	for(int x=1;x<=n;x++)
	for(int y=1;y<=m;y++){
		if(a[x][y])continue;
		int nowU=getHash(x,y);
		for(int k=0;k<=7;k++){
			int nowX=x+dx[k],nowY=y+dy[k];
			if(nowX<1||nowX>n||nowY<1||nowY>m)continue;
			if(a[nowX][nowY])continue;
			int nowV=getHash(nowX,nowY);
			addEdge(nowU,nowV);
		}
	}
	int k=0,pointCnt=n*m;
	for(int i=1;i<=pointCnt;i++){
		if(match[i])continue;
		memset(vis,0,sizeof(vis));
		k+=dfs(i);
	}
	int ans=n*m-t-k;
	printf("%d
",ans);
	return 0;
}
原文地址:https://www.cnblogs.com/zbsy-wwx/p/11680587.html