• [网络流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
    ",dicnic());
    102     return 0;
    103 }
  • 相关阅读:
    Python基础编程常用模块汇总
    博客目录
    网络编程
    python 对象
    python模块和规范开发
    python常用内置函数
    python递归函数和匿名函数
    python装饰器
    python迭代器,生成器,推导式
    python作用域
  • 原文地址:https://www.cnblogs.com/lnxcj/p/10130938.html
Copyright © 2020-2023  润新知