基本概念

二分图有两个种点: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. 分析Tapjoy的模式—分发用于ios设备的企业级应用程序

    下面简单介绍下Tapjoy的模式,供大家参考: Tapjoy最初的合作模式:“按安装奖励”(pay-per-install) Tapjoy利用非常成功的奖励性下载模式影响了App Store的免费游戏 ...

  2. 【Luogu】P2340奶牛会展

    题目链接 突发奇想可以用f[i]表示智商和为i的时候情商最大是多少.这样就变成了一个背包问题. 最后更新答案的时候从0到最大背包容量遍历,最后答案是最大的i+f[i]; 但是虽然答案只能从0到m里选, ...

  3. BZOJ 4503 两个串 ——FFT

    [题目分析] 定义两个字符之间的距离为 (ai-bi)^2*ai*bi 如果能够匹配,从i到i+m的位置的和一定为0 但这和暴力没有什么区别. 发现把b字符串反过来就可以卷积用FFT了. 听说KMP+ ...

  4. gevent 使用踩坑

    简单介绍 gevent 基本概念:   调度器: hub          上下文切换管理: switch          主循环: loop   协程: greenlet gevent 特性:  ...

  5. 【bzoj4320】【ShangHai2006 Homework】【并查集+离线处理】

    ShangHai2006 Homework Time Limit: 10 Sec  Memory Limit: 128 MBSubmit: 918  Solved: 460[Submit][Statu ...

  6. 【shell】shell编程(二)-运算符

    上篇我们学会了如何使用及定义变量.按照尿性,一般接下来就该学基本数据类型的运算了. 没错,本篇就仍是这么俗套的来讲讲这无聊但又必学的基本数据类型的运算了. 基本数据类型运算 操作符 符号 语义 描述 ...

  7. iOS7中Cell高度 Label高度自适应

    
- (float)tableView:(UITableView *)tableView heightForRowAtIndexPath:(NSIndexPath *)indexPath{ NSStr ...

  8. java 文件复制操作

    本案例采用第三方 jar 包完成,commons-io-2.5.jar, 这个 jar 对文件操作非常方便,大家可以尝试使用一下. 这里贴一个简单的 demo 供大家使用 import java.io ...

  9. Iass、Pass、SasS三种云服务区别?

    Iass.Pass.SasS三种云服务区别 我们可以把云计算理解成一栋大楼,而这栋楼又可以分为顶楼.中间.低层三大块.那么我们就可以把Iass(基础设施).Pass(平台).Sass(软件)理解成这栋 ...

  10. 10分钟学会前端工程化(webpack4.0)

    一.概要 1.1.前端工程化 随着前端的不断发展与壮大,前端变得越来越复杂,组件化.模块化.工程化.自动化成了前端发展中不可或缺的一部分,具体到前端工程化,面临的问题是如何提高编码->测试-&g ...