hdu 1045 二分图

二分图简述
    二分图,就是图中可以将点分成两个集合。相同集合的点没有连线,连线仅存在与集合之间的点。
    二分图的匹配,就是二分图中相互没有公共点的线的集合,这些线就叫做匹配边,其端点就是匹配点。最大匹配就是二分图匹配中包含线最多的匹配。完美匹配是指一个匹配中所有的点都是匹配点的匹配。
求一个二分图的最大匹配
    说二分图的最大匹配之前需要认识几个概念。
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]原题

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值