746. [网络流24题] 骑士共存
★★☆ 输入文件:knight.in
输出文件:knight.out
简单对比时间限制:1 s 内存限制:128 MB
-
骑士共存问题
-
«问题描述:
-
在一个n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘
上某些方格设置了障碍,骑士不得进入。
-
«编程任务:
-
对于给定的n*n个方格的国际象棋棋盘和障碍标志,计算棋盘上最多可以放置多少个骑
-
士,使得它们彼此互不攻击。
-
«数据输入:
-
由文件knight.in给出输入数据。第一行有2 个正整数n 和m (1<=n<=200, 0<=m<=n*n)<n2),< span="">
-
分别表示棋盘的大小和障碍数。接下来的m 行给出障碍的位置。每行2 个正整数,表示障
-
碍的方格坐标。
-
«结果输出:
-
将计算出的共存骑士数输出到文件knight.out。
-
输入文件示例 输出文件示例
-
knight.in
-
3 2
-
1 1
3 3
knight.out
-
5
【题解】:
首先把棋盘黑白染色,使相邻格子颜色不同。把所有可用的黑色格子看做二分图X集合中顶点,可用的白色格子看做Y集合顶点。从S向X集合中每个点连接一条容量为1的有向边,从Y集合中每个点向T连接一条容量为1的有向边。从每个可用的黑色格子向骑士一步能攻击到的可用的白色格子连接一条容量为无穷大的有向边。求最小割,结果就是可用格子的数量减去最小割。
【代码】:
#include<cstdio> #include<iostream> using namespace std; const int dx[]={1,1,2,2,-1,-1,-2,-2}; const int dy[]={2,-2,1,-1,2,-2,1,-1}; const int N=210; const int M=N*N; const int inf=0x3f3f3f3f; int n,m,S,T,num,id[N][N],mp[N][N],head[M],dis[M],q[M*5]; struct node{ int v,next,cap; }e[M*10];int tot=1; void add(int x,int y,int z){ e[++tot].v=y;e[tot].cap=z;e[tot].next=head[x];head[x]=tot; e[++tot].v=x;e[tot].cap=0;e[tot].next=head[y];head[y]=tot; } bool bfs(){ for(int i=S;i<=T;i++) dis[i]=inf; int h=0,t=1; q[t]=S;dis[S]=0; while(h!=t){ int x=q[++h]; for(int i=head[x];i;i=e[i].next){ int v=e[i].v; if(e[i].cap&&dis[v]>dis[x]+1){ dis[v]=dis[x]+1; if(v==T) return 1; q[++t]=v; } } } return dis[T]<inf; } int dfs(int x,int f){ if(x==T) return f; int used=0,t; for(int i=head[x];i;i=e[i].next){ int v=e[i].v; if(e[i].cap&&dis[v]==dis[x]+1){ t=dfs(v,min(f,e[i].cap)); //if(!t) dis[t]=0;//TLE*1 e[i].cap-=t;e[i^1].cap+=t; f-=t;used+=t; if(!f) return used; } } dis[x]=0;//TLE*2 return used; } int dinic(){ int res=0; while(bfs()) res+=dfs(S,inf); return n*n-m-res; } void mapping(){ for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ id[i][j]=++num; } } for(int i=1;i<=n;i++){ for(int j=1;j<=n;j++){ if(mp[i][j]) continue; if((i+j)&1^1){//黑 add(S,id[i][j],1); for(int k=0;k<8;k++){ int nx=i+dx[k],ny=j+dy[k]; if(nx<1||nx>n||ny<1||ny>n||mp[nx][ny]) continue; add(id[i][j],id[nx][ny],1); } } else{//白 add(id[i][j],T,1); } } } } int main(){ freopen("knight.in","r",stdin); freopen("knight.out","w",stdout); scanf("%d%d",&n,&m);S=0;T=n*n+1; for(int i=1,x,y;i<=m;i++) scanf("%d%d",&x,&y),mp[x][y]=1; mapping(); printf("%d",dinic()); return 0; }