标签:log tin ott images open 问题 mic uri nod
knight.in
输出文件:knight.out
简单对比
上某些方格设置了障碍,骑士不得进入。
3 3
knight.out
【题解】:
首先把棋盘黑白染色,使相邻格子颜色不同。把所有可用的黑色格子看做二分图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; }
标签:log tin ott images open 问题 mic uri nod
原文地址:http://www.cnblogs.com/shenben/p/6259661.html