题解:骑士共存问题

传送门

对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击

这个题运用奇偶性建图,黑白染色,黑连S,白连T,然后跑最大流,求出最小割,用n2 减去即可。

#include 
#include 
#include 
#include 
#include 
using namespace std;
#define re register
#define gc getchar()
inline int read() {
	re int x=0,f=1;re char ch=gc;
	while(ch<'0'||ch>'9') {if(ch=='-') f=-1;ch=gc;}
	while(ch>='0'&&ch<='9') x=(x<<1)+(x<<3)+(ch^48),ch=gc;
	return x*f;
}
const int N=40010,INF=(1<<29);
struct node {
	int next,to,w;
}e[N<<4];
int h[N],n,cnt=1,s,t,m;
inline void add(int u,int v,int w) {
	e[++cnt]=(node) {h[u],v,w},h[u]=cnt;
	e[++cnt]=(node) {h[v],u,0},h[v]=cnt;
}
#define QXX(u) for(int i=h[u],v;v=e[i].to,i;i=e[i].next)
int deep[N];
inline int bfs() {
	queue<int> q;
	q.push(s);
//	memset(deep,0,sizeof(deep));
	for (int i = 1; i <= t; ++i) deep[i] = 0;
	deep[s]=1;
	while(!q.empty()) {
		int u=q.front();
		q.pop();
		QXX(u) if(e[i].w&&!deep[v]) {
			deep[v]=deep[u]+1;
			q.push(v);
			if(v==t) return 1;
		}
	}
	return 0;
}
int dfs(int u,int flow) {
	if(u==t) return flow;
	int res=flow;
	QXX(u) if(e[i].w&&deep[v]==deep[u]+1) {
		int k=dfs(v,min(res,e[i].w));
		
		e[i].w-=k;
		e[i^1].w+=k;
		res-=k;
	}
	if(res==flow)
		deep[u]=0;
	return flow-res;
}

int ans,maxf,a[220][220],k;
int x[]={1,2,+2,+1,-1,-2,-2,-1};
int y[]={2,1,-1,-2,-2,-1,+1,+2};
#define id(i,j) ((i-1)*n+j)
int main() {
	
//	freopen("x.txt","r",stdin);
	
	n=read(),m=read();
	for(int i=1;i<=m;++i) {
		a[read()][read()]=1;
	}
	s=n*n+1;
	t=s+1;
	for(int i=1;i<=n;++i)
		for(int j=1;j<=n;++j) {
			if(!a[i][j]) {
				re int w=id(i,j);
				if((i+j)&1) {
					add(s,w,1);
					for(int k=0;k<8;++k) {
						re int r=x[k]+i;
						re int c=y[k]+j;
						if(!a[r][c]&&r>0&&r<=n&&c>0&&c<=n)
							add(w,id(r,c),INF);
					}
				}
				else add(w,t,1);
			}
		}
	
	while(bfs()) {
		while((ans=dfs(s,INF))) maxf+=ans;
	}
	cout<<n*n-maxf-m<<endl;
	
	return 0;
}

你可能感兴趣的:(题解,网络流)