[网络流24题]骑士共存问题

题目描述

在一个 n*n个方格的国际象棋棋盘上,马(骑士)可以攻击的棋盘方格如图所示。棋盘上某些方格设置了障碍,骑士不得进入

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

题解

有个定理,大概意思是一个有向图的最小割等于该图的最大流量(说个大概,不严谨)

把每个骑士拆成入点和出点,能互相攻击的连边,求得最大流(最小割)

根据定理,断掉一些边(即在两个互相攻击的骑士只选一个)使骑士们分在两个集合里的最小代价即为最大流量

所以将总骑士数-最大流量即为答案

  1 #include<queue>
  2 #include<cstdio>
  3 #include<cstring>
  4 #include<algorithm>
  5 using namespace std;
  6 int n,m,cnt,tot;
  7 int st,ed;
  8 int dx[8]={1,1,-1,-1,2,2,-2,-2};
  9 int dy[8]={2,-2,2,-2,1,-1,1,-1};
 10 int head[80005];
 11 int cur[80005];
 12 int dis[80005];
 13 bool ban[205][205];
 14 struct node{
 15     int fr;
 16     int to;
 17     int nxt;
 18     int flw;
 19 }edge[1000005];
 20 void init(){
 21     memset(head,-1,sizeof(head));
 22 }
 23 void addedge(int u,int v,int f){
 24     edge[cnt].fr=u;
 25     edge[cnt].to=v;
 26     edge[cnt].flw=f;
 27     edge[cnt].nxt=head[u];
 28     head[u]=cnt++;
 29     edge[cnt].fr=v;
 30     edge[cnt].to=u;
 31     edge[cnt].flw=0;
 32     edge[cnt].nxt=head[v];
 33     head[v]=cnt++;
 34 }
 35 bool bfs(){
 36     queue<int>que;
 37     memset(dis,0x3f,sizeof(dis));
 38     que.push(st);dis[st]=0;
 39     while(!que.empty()){
 40         int u=que.front();
 41         que.pop();
 42         for(int i=head[u];i!=-1;i=edge[i].nxt){
 43             if(!edge[i].flw)continue;
 44             int v=edge[i].to;
 45             if(dis[v]==0x3f3f3f3f){
 46                 dis[v]=dis[u]+1;
 47                 que.push(v);
 48             }
 49         }
 50     }
 51     return (dis[ed]!=0x3f3f3f3f);
 52 }
 53 int dfs(int u,int flw){
 54     int All=0;int tmp;
 55     if(u==ed)return flw;
 56     for(int i=head[u];i!=-1;i=edge[i].nxt){
 57         if(!edge[i].flw)continue;
 58         int v=edge[i].to;head[u]=i;
 59         if(dis[v]!=dis[u]+1)continue;
 60         if((tmp=dfs(v,min(flw,edge[i].flw)))>0){
 61             flw-=tmp;
 62             edge[i].flw-=tmp;
 63             edge[i^1].flw+=tmp;
 64             All+=tmp;
 65             if(!flw)break;
 66         }
 67     }
 68     return All;
 69 }
 70 int dicnic(){
 71     scanf("%d%d",&n,&m);
 72     int ret=0;ed=n*n+1;
 73     for(int i=1;i<=m;i++){
 74         int x,y;
 75         scanf("%d%d",&x,&y);
 76         ban[x][y]=true;
 77     }
 78     for(int i=1;i<=n;i++){
 79         for(int j=1;j<=n;j++){
 80             if(ban[i][j])continue;
 81             for(int k=0;k<8;k++){
 82                 int xx=i+dx[k];
 83                 int yy=j+dy[k];
 84                 if(xx<1||xx>n||yy<1||yy>n)continue;
 85                 if(ban[xx][yy])continue;
 86                 if((i+j)&1)addedge((i-1)*n+j,(xx-1)*n+yy,1);
 87                 else addedge((xx-1)*n+yy,(i-1)*n+j,1);
 88             }
 89             if((i+j)&1)addedge(st,(i-1)*n+j,1);
 90             else addedge((i-1)*n+j,ed,1);
 91         }
 92     }memcpy(cur,head,sizeof(cur));
 93     while(bfs()){
 94         ret+=dfs(st,0x3f3f3f3f);
 95         memcpy(head,cur,sizeof(head));
 96     }
 97     return n*n-m-ret;
 98 }
 99 int main(){
100     init();
101     printf("%d\n",dicnic());
102     return 0;
103 }

 

posted @ 2018-12-17 13:16  Mr_Handsome  阅读(290)  评论(0编辑  收藏  举报