hdu-2255 D - 奔小康赚大钱 题解

question:

传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
这可是一件大事,关系到人民的住房问题啊。村里共有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算法,直接套用模板
#include <cstring>
#include <cstdio>
#include<algorithm> 
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
int qiwang[MAXN][MAXN];   // 记录每个村民对房屋的价值 
int cunmin[MAXN];      
int fangwu[MAXN];       
bool vis_cunmin[MAXN];    // 记录每一轮匹配过的村民 
bool vis_fangwu[MAXN];     // 记录每一轮匹配过的房屋 
int match[MAXN];        
int slack[MAXN];       

int N;


bool dfs(int cm)
{
    vis_cunmin[cm] = true;

    for (int fw = 0; fw < N; ++fw) {

        if (vis_fangwu[fw]) continue; // 每一轮匹配 每个房屋只尝试一次 

        int gap = cunmin[cm] + fangwu[fw] - qiwang[cm][fw];

        if (gap == 0) {  // 如果符合要求
            vis_fangwu[fw] = true;
            if (match[fw] == -1 || dfs( match[fw] )) {    // 找到一个没有匹配的房屋 或者该房屋的村民可以找到其他房屋 
                match[fw] = cm;
                return true;
            }
        } else {
            slack[fw] = min(slack[fw], gap);  
        }
    }

    return false;
}

int KM()
{
    memset(match, -1, sizeof match);    // 初始每个房屋都没有匹配的村民
    memset(fangwu, 0, sizeof fangwu);  

    // 每个村民对房屋的价值 
    for (int i = 0; i < N; ++i) {
        cunmin[i] = qiwang[i][0];
        for (int j = 1; j < N; ++j) {
            cunmin[i] = max(cunmin[i], qiwang[i][j]);
        }
    }

    // 尝试为每一个村民解决房屋问题
    for (int i = 0; i < N; ++i) {

        fill(slack, slack + N, INF);    

        while (1) {
            memset(vis_cunmin, false, sizeof vis_cunmin);
            memset(vis_fangwu, false, sizeof vis_fangwu);

            if (dfs(i)) break;  // 找到房屋,退出 
            int d = INF;
            for (int j = 0; j < N; ++j)
                if (!vis_fangwu[j]) d = min(d, slack[j]);
            for (int j = 0; j < N; ++j) {
                if (vis_cunmin[j]) cunmin[j] -= d;
                if (vis_fangwu[j]) fangwu[j] += d;
                else slack[j] -= d;
            }
        }
    }

    // 匹配完成 求出所有配对的收入的和
    int res = 0;
    for (int i = 0; i < N; ++i)
        res += qiwang[ match[i] ][i];
    return res;
}
int main()
{
    while (~scanf("%d", &N)) {

        for (int i = 0; i < N; ++i)
            for (int j = 0; j < N; ++j)
                scanf("%d", &qiwang[i][j]);
        printf("%d\n", KM());
    }
    return 0;
}        


猜你喜欢

转载自www.cnblogs.com/hrlsm/p/13382872.html