hdu 1045 二分图

来源:互联网 发布:mac邮箱怎么设置签名 编辑:程序博客网 时间:2024/06/05 01:00

二分图简述

    二分图,就是图中可以将点分成两个集合。相同集合的点没有连线,连线仅存在与集合之间的点。    二分图的匹配,就是二分图中相互没有公共点的线的集合,这些线就叫做匹配边,其端点就是匹配点。最大匹配就是二分图匹配中包含线最多的匹配。完美匹配是指一个匹配中所有的点都是匹配点的匹配。

求一个二分图的最大匹配

    说二分图的最大匹配之前需要认识几个概念。
1.交替路
    是从一个非匹配点开始,经过非匹配边、匹配边的一条路径。
2.增广路
    是从一个非匹配点走交替路,途径一个未匹配的点。(如果经过一个未匹配点,交替路就会停在这个未匹配点的位置)这条交替路就是增广路。    增广路有一个特点,就是如果将增广路中的匹配边和非匹配变互换一下,结果仍然是一个匹配,但是匹配边增加了1。
##### 3.匈牙利算法 匈牙利算法主要使用到的特性就是增广路的特点。对于一个二分图的最大匹配,会形成一个匈牙利树,就是树根是一个非匹配点,由根出发每条路都是一个非增广路的交替路。如果一个树存在增广路,则可以使用匹配边和非匹配边互换的方法来消除增广路,从而得到最终的匈牙利树。同时也得到了一个最大匹配。 算法上,一个二分图求匈牙利树的方法主要是对数的遍历的两种方法,DFS和BFS。参考1中由消息的代码和对二分图及其相关知识的详细介绍。#### 二分图法 hdu 1045
上图是题目中的区域,这个图如何能和二分图联系起来呢? 思考一个问题,如果没有墙壁。是不是可以认为题目变成了一个全链接的二分图,求最大匹配。全链接的两个集合分别是行(1,2,3,4)和列(1,2,3,4)。最终可以找到四个位置来放城堡。 但是题目中的矩形区域内存在墙壁,墙壁具有阻隔的作用。也就是有墙壁导致每行和每列可以放置不止一个城堡。我们改如果巧妙的将这个问题转化成二分图的问题呢?关键问题出现了。 可以做如下的思考,如果没有墙壁。结果就成了每行可以使用一个行号来表示,并且只能和一个列号链接。如果由了墙壁则会出现一个行号可以和多个列号链接从而产生匹配。所以就有了一个很巧妙的方法:把同一行被墙壁阻隔的相连的区域标记为一个号,如下图所示。
形成一个二分图:
    这样就可以使用二分图的方法来求解了。这个思路太巧妙了,有点难以想到。    下面给出了对应的代码:
//转化为二分图//map 为上面的地图         int a=1 ,b=1,flag = 0;         for(int i=0;i<n;i++)         {              for(int j=0;j<n;j++)              {                  while(map[i][j]=='.'&&j<n)  flag=1 , aa[i][j]=a , j++;                  if(flag==1) a++ , flag=0;              }              for(int j=0;j<n;j++)              {                   while(map[j][i]=='.'&&i<=n) { flag=1 , bb[j][i]=b , j++;}                   if(flag==1) b++ ; flag = 0;              }         }         for(int i=0;i<n;i++)         {             for(int j=0;j<n;j++)             {                  if(map[i][j]=='.')  cc[aa[i][j]][bb[i][j]] = cc[bb[i][j]][aa[i][j]] = 1;             }         }//dfs求解最大匹配//此dfs理解起来还是有点难度,望各位加油int find_match(int u , int b){    for(int i=1;i<=b;i++)    {        if(cc[u][i]==1 && vis[i]==0)        {            vis[i]=1;            if(pp[20+i]==0 || find_match(pp[20+i] , b))            {                pp[20+i] = u; pp[u]=i;                return 1;            }        }    }    return 0;}int find_path(int a  , int b){    int match = 0;    memset(pp,0 ,sizeof(pp));    for(int i=1;i<=a;i++)    {        if(pp[i]==0)        {             memset(vis,0,sizeof(vis));             match+= find_match(i,b);        }    }    return match;}

此题可以使用,BFS来求解,望博友自行完成,必然有所精进。水平有限,如果博文有错误或者是有更好的方法,请各位看官不吝赐教。

参考

[1]二分图的最大匹配、完美匹配和匈牙利算法
[2]HDU 1045 二分图匹配
[3]原题

原创粉丝点击