P3355 骑士共存问题
题目描述
在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入
对于给定的 n*n 个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑士,使得它们彼此互不攻击
输入格式
第一行有 2 个正整数n 和 m (1<=n<=200, 0<=m<n2),分别表示棋盘的大小和障碍数。接下来的 m 行给出障碍的位置。每行 2 个正整数,表示障碍的方格坐标。
输出格式
将计算出的共存骑士数输出
输入输出样例
输入 #1
3 2 1 1 3 3
输出 #1
5
黑白染色构图,能攻击到的就连一条inf的边,跑一遍最大流
#include<bits/stdc++.h> #define inf 0x3f3f3f3f using namespace std; const int maxn = 200*201; int dx[]={-2,-2,-1,1,2,2,1,-1},dy[]={-1,1,2,2,1,-1,-2,-2}; int n,m,head[maxn],size,cur[maxn],dep[maxn],s,t; bool ok[220][220]; struct edge{ int v,nex,flow; }e[3000010*2]; void adde(int u,int v,int flow){ e[size].v=v;e[size].nex=head[u];e[size].flow=flow;head[u]=size++; } bool bfs(){ memset(dep,-1,sizeof(dep)); dep[s]=0;queue<int> q; q.push(s); while(!q.empty()){ int u=q.front();q.pop(); for(int i=head[u];~i;i=e[i].nex){ int v=e[i].v; if(dep[v]==-1&&e[i].flow){ dep[v]=dep[u]+1; q.push(v); } } } return dep[t]!=-1; } int dfs(int u,int f){ if(u==t) return f; int used=0; for(int& i=cur[u];~i;i=e[i].nex){ int v=e[i].v; if(e[i].flow&&dep[v]==dep[u]+1){ int d=dfs(v,min(e[i].flow,f-used)); used+=d;e[i].flow-=d;e[i^1].flow+=d; if(used==f) break; } } return used; } int dinic(){ int res=0; while(bfs()){ for(int i=0;i<=n*n+1;i++) cur[i]=head[i]; res+=dfs(s,inf); } return res; } int main(){ // freopen("in.txt","r",stdin); s=0;t=n*n+1; scanf("%d%d",&n,&m); memset(head,-1,sizeof(head)); for(int i=1;i<=m;i++) { int x,y;scanf("%d%d",&x,&y); ok[x][y]=1; } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(ok[i][j]) continue; if((i+j)&1) { adde(s,(i-1)*n+j,1);adde((i-1)*n+j,s,0); }else { adde((i-1)*n+j,t,1);adde(t,(i-1)*n+j,0); } } for(int i=1;i<=n;i++) for(int j=1;j<=n;j++){ if(((i+j)&1)==0) continue;//不要写成if((i+j)&1==0) for(int k=0;k<=7;k++){ int ex=dx[k]+i,ey=dy[k]+j; if(ex>n||ex<1||ey>n||ey<1) continue; if(ok[ex][ey]) continue; adde((i-1)*n+j,(ex-1)*n+ey,inf);adde((ex-1)*n+ey,(i-1)*n+j,0); } } printf("%d",n*n-m-dinic()); }