HDU 2255 奔小康赚大钱(KM算法求完备匹配)

Problem Description:

传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到一间房子且只能得到一间房子。
另一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.由于老百姓都比较富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比如有3间房子,一家老百姓可以对第一间出10万,对第2间出2万,对第3间出20万.(当然是在他们的经济范围内).现在这个问题就是村领导怎样分配房子才能使收入最大.(村民即使有钱购买一间房子但不一定能买到,要看村领导分配的).

Input:

输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。

Output:

请对每组数据输出最大的收入值,每组的输出占一行。

Sample Input:

2

100 10

15 23

Sample Output:

123

KM算法小结来源(具体操作):http://www.myexception.cn/program/1401423.html

#include<stdio.h>
#include<string.h>
#include<algorithm>
#define INF 0x3f3f3f3f
#define N 310
using namespace std;
int G[N][N], s[N], n;
int visx[N], visy[N], use[N];
int lx[N], ly[N];
int Find(int u) //查询u是否存在完备匹配
{
    int i;
    visx[u] = 1;
    for (i = 1; i <= n; i++)
    {
        if (!visy[i] && G[u][i] == lx[u]+ly[i]) //当村庄i没有被查询,且u到i的权值刚好是最大权值
        {
            visy[i] = 1;
            if (!use[i] || Find(use[i])) //如果村庄i还有被匹配或者与i的匹配的点还能与其它点进行匹配
            {
                use[i] = u; //则可以将与i匹配的点换成u
                return 1; //代表u存在完备匹配
            }
        }
        else s[i] = min(s[i], (lx[u]+ly[i])-G[u][i]); //只有当G[u][i]越大是得到的s[i]越小,才能让权值更新范围d变小,继续下一次查询
    }
    return 0;
}
int KM()
{
    int i, j, ans = 0, d;
    memset(lx, 0, sizeof(lx));
    memset(ly, 0, sizeof(ly));
    for (i = 1; i <= n; i++)
    {
        for (j = 1; j <= n; j++)
            lx[i] = max(lx[i], G[i][j]);
    } //为了便于比较权值和更大的匹配,要保证(lx[i]+ly[j])>=G[i][j]
    for (i = 1; i <= n; i++)    //那么lx数组可以初始化为与i相连的最大权值,ly数组初始化为0
    {
        while (1) //只要村民i没有找到能与之形成完备匹配的村庄j,就一直执行循环
        {
            memset(visx, 0, sizeof(visx));
            memset(visy, 0, sizeof(visy)); //每一次查找是否有完备匹配,都是从头开始,每次必须初始化
            for (j = 1; j <= n; j++)
                s[j] = INF;
            if (Find(i))
                break; //当找到完备匹配时就可以跳出循坏
            d = INF;
            for (j = 1; j <= n; j++)
            {
                if (!visy[j])
                    d = min(d, s[j]); //更新d的值,让它最小
            }
            for (j = 1; j <= n; j++)
            {
                if (visx[j]) lx[j] -= d;
                if (visy[j]) ly[j] += d; //扩充相等子图(相等子图:为完备匹配中所有的匹配, 即所有的村民i和与之相匹配的村庄j)
            }
        }
    }
    for (i = 1; i <= n; i++)
        ans += G[use[i]][i]; //每次加上完备匹配的权值就是最大权值
    return ans;
}
int main ()
{
    int i, j, ans;
    while (scanf("%d", &n) != EOF)
    {
        memset(G, 0, sizeof(G));
        memset(use, 0, sizeof(use));
        for (i = 1; i <= n; i++)
        {
            for (j = 1; j <= n; j++)
                scanf("%d", &G[i][j]);
        }
        ans = KM();
        printf("%d\n", ans);
    }
    return 0;
}
时间: 2024-08-03 07:26:03

HDU 2255 奔小康赚大钱(KM算法求完备匹配)的相关文章

hdu 2255 奔小康赚大钱 (km算法模板)

题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=2255 解题思路: 了解km算法以后,就可以直接套用km算法,km算法:完备匹配下的最大权匹配, 代码: 1 #include <cstdio> 2 #include <cstring> 3 #include <iostream> 4 #include <algorithm> 5 using namespace std; 6 7 #define maxn 310

HDU 2255 奔小康赚大钱 KM算法题解

KM算法求的是完备匹配下的最大权匹配,是Hungary算法的进一步,由于Hungary算法是最大匹配的算法,不带权. 经典算法,想不出来的了,要參考别人的.然后消化吸收吧. 由于真的非常复杂的算法. 我理解算法匹配思想: 1 開始的时候,全部边都记录自己的最优匹配,无论有没有冲突 2 递归循环的时候.假设找不到自己的最优匹配,那么就找次要匹配 3 次要匹配不行,继续找下一个次优匹配,全部点都一定要找到解 难点: 怎样记录这些信息,以便循环处理全部点. 牵涉到非常多什么增广路,交错树之类的,名词,

hdu 2255奔小康赚大钱 KM算法模板

题目链接:http://acm.hdu.edu.cn/showproblem.php? pid=2255 一,KM算法:(借助这个题写一下个人对km的理解与km模板) KM算法主要是用来求解图的最优匹配的. 1.带权二分图:  在二分图中每一条边(x.y)相应一个权值Wi这样的二分图叫带权二分图. 一个匹配的权值就是该匹配中全部边的权值之和. 2,最优匹配: 权值最大的一个完美匹配.叫做最优匹配.       <km算法思想> 对于一个带权全然二分图:G(V.E),对于当中每一条边(x.y)边

HDU 2255 奔小康赚大钱 KM算法的简单解释

KM算法一般用来寻找二分图的最优匹配. 步骤: 1.初始化可行标杆 2.对新加入的点用匈牙利算法进行判断 3.若无法加入新编,修改可行标杆 4.重复2.3操作直到找到相等子图的完全匹配. 各步骤简述: 1.根据二分图建立2个可行标杆; lx为x的可行标杆,初始化lx[i]为与i点相连的最大边 ly为y的可行标杆,初始化为0. 可行性的判断条件应为lx[x]+ly[y] >= Map[x][y]. 2.对于新加入的点用匈牙利算法经行判断,确定改点能否加入旧子图中,形成新子图. 对于该加入的点有两种

HDU 2255 奔小康赚大钱 KM裸题

#include <stdio.h> #include <string.h> #define M 310 #define inf 0x3f3f3f3f int n,nx,ny; int link[M],lx[M],ly[M],slack[M]; //lx,ly为顶标,nx,ny分别为x点集y点集的个数 int visx[M],visy[M],w[M][M]; int DFS(int x) { visx[x] = 1; for (int y = 1;y <= ny;y ++)

hdu 2255 奔小康赚大钱(KM算法)

奔小康赚大钱 Time Limit: 1000/1000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others) Total Submission(s): 3248    Accepted Submission(s): 1413 Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考

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

/** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) km算法 模板来自:http://www.cnblogs.com/wenruo/p/5264235.html 如果是求最小权完美匹配,那么将所有权值取相反数,然后求得最大权,输出最大权的相反数即可. */ #include <iostream> #include <cstring> #

HDU 2255 ——奔小康赚大钱——————【KM算法裸题】

奔小康赚大钱 Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u Submit Status Practice HDU 2255 Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子. 这可是一件大事,关系到人民的住房问题啊.村里共有n间房间,刚好有n家老百姓,考虑到每家都要有房住(如果有老百姓没房子住的话,容易引起不安定因素),每家必须分配到

[ACM] HDU 2255 奔小康赚大钱 (二分图最大权匹配,KM算法)

奔小康赚大钱 Problem Description 传说在遥远的地方有一个很富裕的村落,有一天,村长决定进行制度改革:又一次分配房子. 这但是一件大事,关系到人民的住房问题啊. 村里共同拥有n间房间,刚好有n家老百姓,考虑到每家都要有房住(假设有老百姓没房子住的话.easy引起不安定因素),每家必须分配到一间房子且仅仅能得到一间房子. 还有一方面,村长和另外的村领导希望得到最大的效益,这样村里的机构才会有钱.因为老百姓都比較富裕,他们都能对每一间房子在他们的经济范围内出一定的价格,比方有3间房