基本概念

二分图有两个种点: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. mvc框架简介

    1.mvc( mode  view controller)是什么?   m指业务代码,v指用户界面,c是控制器 使用MVC的目的是将M和V的实现代码分离,从而使同一个程序可以使用不同的表现形式 是一种 ...

  2. uva 11235 RMQ范围最大值

    题目大意:给一个整数上升序列,对于一系列询问区间(i,j),回答这段区间出现次数最多值所出现的次数. 分析:一个上升序列,相同的值聚集在一起,把相同的值的区间看作一个整体,假设这样的整体有n个,把他们 ...

  3. hdu 4960 记忆化搜索 DP

    Another OCD Patient Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 131072/131072 K (Java/Ot ...

  4. 再看c语言之getchar/putchar

  5. CodeChef - LEMOVIE Little Elephant and Movies

    Read problems statements in Mandarin Chineseand Russian. Little Elephant from Zoo of Lviv likes to w ...

  6. Java 复制字符串到系统剪贴板

    原文:http://www.open-open.com/code/view/1453188435933 public static void main(String[] args) { StringS ...

  7. 实现uitable cell中点击button设置当前cell为选中状态

    - (void)buttonClick:(id)senser{    NSInteger tag = [senser tag];    NSLog(@"the button tag is % ...

  8. BUPT复试专题—中序遍历序列(2013)

    题目描述 给出一个序列,判断该序列是不是某二叉搜索树的中序遍历序列,如果是输出"Yes",否则输出"No".一颗带权二叉树是一颗二叉搜索树(二叉排序树),当且仅 ...

  9. 转: 在CentOS 6.X 上面安装 Python 2.7.X

    转:https://ruiaylin.github.io/2014/12/12/python%20update/ 评注: yum -y update //这个更新太坑了,1120更新包...想死的心都 ...

  10. [Javascript] Cancel A Promise Using AbortController

    The AbortController interface enables us to cancel a one or more DOM requests. In this lesson, we wi ...