基本概念

二分图有两个种点:X和Y。X与Y之间存在一些边,每个边有一个权值。现要求求一组X与Y间的通过边实现的一一匹配,使得得到的边权和最大。

总体过程

对每个X节点设置一个顶标Xl,初值为与X相邻的边的权值最大值;Y节点设置一个顶标Yl,初值为0。当前情况下,如果Xl[x]+Yl[x]==weight[x][y],则此时的边(x,y)为可匹配边。weight[x][y]越接近Xl[x]+Yl[y],则边(x,y)越有可能为匹配边。

枚举每一个X,对以下步骤循环:对于当前图所有可匹配的边所形成的子图用匈牙利算法进行交错路径搜索。搜索到了交错路径那皆大欢喜,把交错路径上的匹配边翻转一下,重新设置与y节点匹配的x,便完成了对当前X的匹配;否则,更改原有的匹配方式,使得边权和变小的程度尽量小,且匹配的边数不变,再接着找交错路径……。此过程一直持续到寻找到交错路径为止。

如何更改原有的匹配方式?

利用匈牙利算法中访问的节点标记,在访问到的X节点和未访问到的Y节点中找到一对x和y,使得delta=xl[x]+yl[y]-weight[x][y]最小,然后将Vis标记过的Xl[x]-=delta, Yl[y]+=delta,此时Xl[x]+Yl[y]==weight[x][y],相当于将xy匹配,并将原先与y相连的x'节点断开。其他边不变。这样匹配边的总数不变。

对于delta,我们可以再在FindPath中把所有x节点的delta最小值预先算出来。

注意事项

  • Xl[x]+Yl[y]>=XYweight[x][y]。
  • 最后统计边权和时,按照YmatchX搜索,而不是通过可匹配边(Xl[x]+Yl[y]==weight[x][y])搜索。
  • X也有Vis,求交错路径时不要忘了设置X的Vis。
  • FindPath算Delta时,else后的内容应当放在if(Xl[x]+Yl[y]==XYweight[x][y])下,而不是if(!Yvis[y])因为delta的定义是vis过的x与没有vis过的y的最小delta值
  • 设置Yvis=true应当放在if(Xl[x]+Yl[y]==XYweight[x][y])内,而不是其外部、if(!Yvis[y])内。因为只有Xl[x]+Yl[y]==XYweight[x][y]时边(x,y)才是匹配边。
  • #include <cstdio>
    #include <cstring>
    #include <algorithm>
    using namespace std; const int MAX_X = 1010, MAX_Y = 1010, INF = 0x3f3f3f3f;
    #define LOOP(i, n) for(int i=1; i<=n; i++) struct KM
    {
    int XYweight[MAX_X][MAX_Y];
    int YmatchX[MAX_Y];
    int Xl[MAX_X], Yl[MAX_Y];
    int Delta[MAX_X];
    bool Yvis[MAX_Y], Xvis[MAX_X];
    int totX, totY; bool FindPath(int x)
    {
    Xvis[x] = true;
    LOOP(y, totY)
    {
    if (!Yvis[y])
    {
    if (Xl[x] + Yl[y] == XYweight[x][y])
    {
    Yvis[y] = true;
    if (!YmatchX[y] || FindPath(YmatchX[y]))
    {
    YmatchX[y] = x;
    return true;
    }
    }
    else
    Delta[x] = min(Delta[x], Xl[x] + Yl[y] - XYweight[x][y]);
    }
    }
    return false;
    } int Proceed()
    {
    memset(YmatchX, 0, sizeof(YmatchX));
    memset(Xl, 0, sizeof(Xl));
    memset(Yl, 0, sizeof(Yl));
    LOOP(x, totX)
    LOOP(y, totY)
    Xl[x] = max(Xl[x], XYweight[x][y]);
    LOOP(firstX, totX)
    {
    while (true)
    {
    memset(Xvis, false, sizeof(Xvis));
    memset(Yvis, false, sizeof(Yvis));
    memset(Delta, INF, sizeof(Delta));
    if (FindPath(firstX))
    break;
    int delta = INF;
    LOOP(x, totX)
    if (Xvis[x])
    delta = min(delta, Delta[x]);
    if (delta == INF)
    break;
    LOOP(x, totX)
    if (Xvis[x])
    Xl[x] -= delta;
    LOOP(y, totY)
    if (Yvis[y])
    Yl[y] += delta;
    }
    }
    int ans = 0;
    LOOP(y, totY)
    if (YmatchX[y])
    ans += XYweight[YmatchX[y]][y];
    return ans;
    }
    }g; int main()
    {
    int tot;
    while (~scanf("%d", &tot))
    {
    g.totX = tot;
    g.totY = tot;
    LOOP(x, tot)
    {
    LOOP(y, tot)
    {
    int w;
    scanf("%d", &w);
    g.XYweight[x][y] = w;
    }
    }
    printf("%d\n", g.Proceed());
    }
    return 0;
    }

      

  

HDU2255 奔小康赚大钱 【模板】 二分图完美匹配的更多相关文章

  1. HDU2255 奔小康赚大钱 (最大权完美匹配) 模板题【KM算法】

    <题目链接> 奔小康赚大钱 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊 ...

  2. HDU2255 奔小康赚大钱【二分图最佳匹配】

    题目链接: http://acm.hdu.edu.cn/showproblem.php? pid=2255 题目大意: 村里要分房子. 有N家老百姓,刚好有N间房子.考虑到每家都要有房住,每家必须分配 ...

  3. hdu-2255.奔小康赚大钱(最大权二分匹配)

    奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)Total Subm ...

  4. Hdu2255 奔小康赚大钱(二分图最大权匹配KM算法)

    奔小康赚大钱 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好 ...

  5. hdu2255 奔小康赚大钱,最大权匹配,KM算法

    点击打开链接 最大权匹配 KM算法 算法步骤: 设顶点Xi的顶标为a[i],顶点Yi的顶标为b[i] ⅰ.初始时.a[i]为与Xi相关联的边的最大权值.b[j]=0.保证a[i]+b[j]>=w ...

  6. hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)

    /** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) ...

  7. HDU2255 奔小康赚大钱 —— 二分图最大权匹配 KM算法

    题目链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    ...

  8. hdu2255 奔小康赚大钱 二分图最佳匹配--KM算法

    传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子.这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住 ...

  9. HDU2255 奔小康赚大钱 【KM算法】

    题意: 每个人对不同房有不同出价,就是就是怎样匹配卖房让收入达到最大. 思路: 建立二分图,一边为N家老百姓,还有一边为N间房子.对老百姓和房子之间估价建立一条有带权边.问题就转变为了再二分图中找出一 ...

  10. [hdu2255] 奔小康赚大钱

    Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有 \(n\) 间房间,刚好有 \(n\) 家 ...

随机推荐

  1. BZOJ 4719 [Noip2016]天天爱跑步 ——树链剖分

    一直以为自己当时是TLE了,但是再看发现居然WA? 然后把数组扩大一倍,就A掉了.QaQ 没什么好说的.一段路径分成两段考虑,上升的一段深度+时间是定值,下降的一段深度-时间是定值,然后打标记统计即可 ...

  2. BZOJ 2127 happiness ——网络流

    [题目分析] 基本上是第一次真正的使用最小割的模型. 同时加上一个数然后最后再减去是处理负数的一种方法. 设立出来最小割的模型然后解方程是一件很重要的事情,建议取一个相对来说比较简单的值带入求解. 这 ...

  3. cf682E Alyona and Triangles

    You are given n points with integer coordinates on the plane. Points are given in a way such that th ...

  4. CI(CodeIgniter)框架中的增删改查操作

    我们创建一个模型( 项目目录/models/),请注意:模型名与文件名相同且必须继承数据核心类CI_Model,同时重载父类中的构造方法 CodeIgniter的数据函数类在 \models\User ...

  5. 更改navigationBar 颜色

    
 
 if (IS_IOS7()) { /* iOS7 时 Navigation 颜色 */ [[UINavigationBar appearance] setBarTintColor: HexCo ...

  6. hdu 3594 Cactus /uva 10510 仙人掌图判定

    仙人掌图(有向):同时满足:1强连通:2任何边不在俩个环中. 个人理解:其实就是环之间相连,两两只有一个公共点,(其实可以缩块),那个公共点是割点.HDU数据弱,网上很多错误代码和解法也可以过. 个人 ...

  7. 王垠:完全用Linux工作 (2003)

    完全用Linux工作,抛弃windows 我已经半年没有使用 Windows 的方式工作了.Linux 高效的完成了我所有的工作. GNU/Linux 不是每个人都想用的.如果你只需要处理一般的事务, ...

  8. FireDac心得

    usesFireDAC.Phys.MySQL, FireDAC.Stan.Def, FireDAC.DApt, FireDAC.Comp.Client, FireDAC.Comp.UI, FireDA ...

  9. Jenkins持续部署-Windows环境持续部署探究1

    目录 Jenkins持续部署-Windows环境持续部署探究1 目录 前言 目的 方案流程 技术实现 PowerShell FTP上传插件 环境变量插件 脚本执行 远程调用 升级服务 启动服务 总结 ...

  10. Nginx配置文件语法教程

    Nginx的配置文件在一开始可能真的不太好理解,就像当初开始使用Apache那样,像JSON但却不是.可以说是Nginx的一种专门语言,仅为Nginx服务的. 市面上基本都是写了一点不写一点的教程,基 ...