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

奔小康赚大钱

Time Limit:1000MS     Memory Limit:32768KB     64bit IO Format:%I64d & %I64u

Submit Status Practice HDU 2255

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

解题思路:最优完美匹配。套模板就行了。

#include<stdio.h>
#include<algorithm>
#include<string.h>
#include<vector>
using namespace std;
const int maxn = 550;
const int INF = 0x3f3f3f3f;
int nx, ny, lx[maxn], ly[maxn];
bool visx[maxn], visy[maxn];
int linker[maxn], slack[maxn];
int G[maxn][maxn];
bool dfs(int x){
    visx[x] = 1;                    //标记X的匈牙利树节点
    for(int y = 1; y <= ny; y++){
        if(visy[y]) continue;
        int tmp = lx[x] + ly[y] - G[x][y];
        if(tmp == 0){   //找到了一条可以加入相等子图的新边
            visy[y] = 1;    //标记Y的匈牙利树节点
            if(linker[y] == -1 || dfs(linker[y])){  //找到了增广路
                linker[y] = x;
                return true;
            }
        }else if(slack[y] > tmp){       //更新松弛量
            slack[y] = tmp;
        }
    }
    return false;
}
int KM(){
    memset(linker,-1,sizeof(linker));   //匹配数组
    memset(ly,0,sizeof(ly));            //初始化Y节点顶标
    for(int i = 1; i <= nx; i++){
        lx[i] = -INF;
        for(int j = 1; j <= ny; j++){
            if(lx[i] < G[i][j]){
                lx[i] = G[i][j];        //初始化X节点顶标
            }
        }
    }
    for(int x = 1; x <= nx; x++){       //找每个X的增广路
        for(int i = 1; i <= ny; i++){   //初始化松弛量
            slack[i] = INF;
        }
        while(true){
            memset(visx,0,sizeof(visx));
            memset(visy,0,sizeof(visy));
            if(dfs(x)) break;               //找到了增广路
            int d = INF;
            for(int i = 1; i <= ny; i++){
                if(!visy[i] && d > slack[i]){   //Yi不在匈牙利树(交错树)中
                    d = slack[i];
                }
            }
            for(int i = 1; i <= nx; i++){       //Xi在匈牙利树中,更新顶标
                if(visx[i]){
                    lx[i] -= d;
                }
            }
            for(int i = 1; i <= ny; i++){
                if(visy[i]){                //Yi在匈牙利树中,更新顶标
                    ly[i] += d;
                }else{                      //更新松弛量
                    slack[i] -= d;
                }
            }
        }
    }
    int ret = 0;
    for(int i = 1; i <= ny; i++){          //求和
        if(linker[i] != -1){
            ret += G[linker[i]][i];
        }
    }
    return ret;
}
int main(){
    int n;
    while(scanf("%d",&n)!=EOF){
        memset(G,0,sizeof(G));
        int c;
        for(int i = 1; i <= n; i++){
            for(int j = 1; j <= n; j++){
                scanf("%d",&c);
                G[i][j] = c;
            }
        }
        nx = ny = n;
        int res = KM();
        printf("%d\n",res);
    }
    return 0;
}

  

时间: 2025-01-18 11:16:24

HDU 2255 ——奔小康赚大钱——————【KM算法裸题】的相关文章

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算法模板)

题目链接: 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算法一般用来寻找二分图的最优匹配. 步骤: 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算法求完备匹配)

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

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

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

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> #

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

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