zoukankan      html  css  js  c++  java
  • hoj 1086 Don't Get Rooked 二分图匹配

    /*

    题目:

       象棋中的车在象棋盘上可以放置的最大数目(若没有挡板的话,在同一行或同一列的车

       可以相互攻击,问的是所有的车可以和平地放置的最大数目)

     

    分析:

       方法一:

          可以通过暴搜得到答案(题目数据较小)

       方法二:

          可以通过构造二分图的方法来做,以下主要分析二分图的解法

     

    方法:

       我们将每一行,每一列被墙隔开,且包含空地的连续区域称作。显然,在一个块之中,

       最多只能放一个车。我们把这些块编上号。

       同样,把竖直方向的块也编上号。

       把每个横向块看作X部的点,竖向块看作Y部的点,若两个块有公共的空地,则在它们之间连边。

       于是,问题转化成这样的一个二部图:

     

       .X..

       ....

       XX..

       ....

     

       我们可以给上面的图形标号(X部):r[i][j]

       1  -1   2   2

       3   3   3   3

       -1 -1   4   4

       5   5   5   5

     

       接着对Y部进行标号(Y部):c[i][j]

       1  -1  5  6

       1   3  5  6

       -1 -1  5  6

       2   4  5  6

       若该位置上不为隔板,则只需对g[r[i][j]][c[i][j]] = true即可构建

       一个二分图,剩下的就是赤裸裸的hungry算法了。

     

       现在转为对数组c和数组r的计算问题,其实我们可以枚举每一个位置上是否为

       空地,若为空地则r[i][j] = n(n为当前的最大标号),每当遇到隔板时,设旗帜

       为真,每当遇到新的空地时,先对n加一,在赋值给r[i][j],列的同理计算。

       另外需注意如此做法的数组g(标记有没有连线)的最大下标会发生变化,即最大值

       会大于4而不会大于164*4

     

    */

    //#include <iostream>//发现每次去掉这两句时,内存都会少400k

    #include <cstdio>

    #include <cstring>

    //using namespace std;

    #define X 20

    int ym[X],c[X][X],r[X][X],n,m;

    bool g[X][X],use[X];

    bool dfs(int u)          //寻找增广轨算法

    {

       int t;

       for(int v=1;v<=m;v++)

          if(g[u][v]&&!use[v])

          {

             use[v] = true;

             t = ym[v];

             ym[v] = u;         //通过取反操作尝试能不能找到增广轨

             if(t==-1||dfs(t))  //能够找到的话

                return true;

             ym[v] = t;         //不能找到的话,付回原值

          }

          return false;

    }

    int hungry()       //匈牙利算法

    {

       int ret = 0;

       memset(ym,-1,sizeof(ym));

       for(int u=1;u<=n;u++)//从顶点u开始看看能不能找到一条增广路

       {

          memset(use,false,sizeof(use));//能找到的话,匹配加1

          if(dfs(u))

             ret++;

       }

       return ret;

    }

    int main()

    {

       freopen("sum.in","r",stdin);

       freopen("sum.out","w",stdout);

       int t;

       char ch[X][X];

       while(scanf("%d",&t),t)

       {

          for(int i=0;i<t;i++)

             scanf("%s",ch[i]);

          memset(g,false,sizeof(g));

          n = m = 0;

          bool flag;

          memset(r,0,sizeof(r));

          for(int i=0;i<t;i++)

          {

             flag = true;

             for(int j=0;j<t;j++)     //算行的标号

             {

                if(ch[i][j]=='.')

                {

                    if(flag)        //如果为真,表明前面有隔板,说明标号比前面的大1

                       n++;

                    r[i][j] = n;    //赋值

                    flag = false;

                }

                else               //设立旗帜

                {

                    flag = true;

                    r[i][j] = -1;

                }

             }

             flag = true;

             for(int j=0;j<t;j++)  //寻找列的标号

             {

                if(ch[j][i]=='.')

                {

                    if(flag)

                       m++;

                    flag = false;

                    c[j][i] = m;

                }

                else

                {

                    flag = true;

                    c[j][i] = -1;

                }

             }

          }

          for(int i=0;i<t;i++)

             for(int j=0;j<t;j++)

                if(c[i][j]!=-1&&r[i][j]!=-1)

                    g[r[i][j]][c[i][j]] = true;//构造连线

          printf("%d\n",hungry());

       }

       return 0;

    }

     

  • 相关阅读:
    OpenCV学习:图片的读取、展示
    Windows下使用Anaconda配置opencv和tensorflow环境
    二叉树的链式存储的实现以及对二叉树的各种操作
    数据结构——树笔记1
    Python学习笔记整理总结【Django】Ajax
    Python学习笔记整理总结【Django】:中间件、CSRF、缓存
    Python学习笔记整理总结【Django】:模板语言、分页、Cookie、Session
    Python学习笔记整理总结【Django】:Model操作(一)
    Python学习笔记整理总结【Django】【MVC/MTV/路由分配系统(URL)/视图函数 (views)/表单交互】
    数据结构与算法(C/C++版)【树与二叉树】
  • 原文地址:https://www.cnblogs.com/yejinru/p/2436393.html
Copyright © 2011-2022 走看看