zoukankan      html  css  js  c++  java
  • 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
    ", ans);
        }
        return 0;
    }
     
  • 相关阅读:
    Python 安装Twisted 提示python version 2.7 required,which was not found in the registry
    Openfire Strophe开发中文乱码问题
    css div 垂直居中
    How to create custom methods for use in spring security expression language annotations
    How to check “hasRole” in Java Code with Spring Security?
    Android 显示/隐藏 应用图标
    Android 当媒体变更后,通知其他应用重新扫描
    文件上传那些事儿
    专题:点滴Javascript
    主流动画实现方式总结
  • 原文地址:https://www.cnblogs.com/syhandll/p/4713880.html
Copyright © 2011-2022 走看看