Interesting Housing Problem HDU - 2426(KM算法求n对m匹配)

时间:2019-10-23
本文章向大家介绍Interesting Housing Problem HDU - 2426(KM算法求n对m匹配),主要包括Interesting Housing Problem HDU - 2426(KM算法求n对m匹配)使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
For any school, it is hard to find a feasible accommodation plan with every student assigned to a suitable apartment while keeping everyone happy, let alone an optimal one. Recently the president of University ABC, Peterson, is facing a similar problem. While Peterson does not like the idea of delegating the task directly to the class advisors as so many other schools are doing, he still wants to design a creative plan such that no student is assigned to a room he/she dislikes, and the overall quality of the plan should be maximized. Nevertheless, Peterson does not know how this task could be accomplished, so he asks you to solve this so-called "interesting" problem for him.
Suppose that there are N students and M rooms. Each student is asked to rate some rooms (not necessarily all M rooms) by stating how he/she likes the room. The rating can be represented as an integer, positive value meaning that the student consider the room to be of good quality, zero indicating neutral, or negative implying that the student does not like living in the room. Note that you can never assign a student to a room which he/she has not rated, as the absence of rating indicates that the student cannot live in the room for other reasons.
With limited information available, you've decided to simply find an assignment such that every student is assigned to a room he/she has rated, no two students are assigned to the same room, and the sum of rating is maximized while satisfying Peterson's requirement. The question is … what exactly is the answer?

InputThere are multiple test cases in the input file. Each test case begins with three integers, N, M, and E (1 <= N <= 500, 0 <= M <= 500, 0 <= E <= min(N * M, 50000)), followed by E lines, each line containing three numbers, S i, R i, V i, (0 <= S i < N, 0 <= R i < M, |V i| <= 10000), describing the rating V i given by student S i for room R i. It is guaranteed that each student will rate each room at most once.
Each case is followed by one blank line. Input ends with End-of-File.
OutputFor each test case, please output one integer, the requested value, on a single line, or -1 if no solution could be found. Use the format as indicated in the sample output.
Sample Input
3 5 5
0 1 5
0 2 7
1 1 6
1 2 3
2 4 5

1 1 1
0 0 0

1 1 0
Sample Output
Case 1: 18
Case 2: 0
Case 3: -1

#include <iostream>
#include <cstring>
#include <cstdio>

using namespace std;
const int MAXN = 505;
const int INF = 0x3f3f3f3f;

int love[MAXN][MAXN];   // 记录每个妹子和每个男生的好感度
int ex_girl[MAXN];      // 每个妹子的期望值
int ex_boy[MAXN];       // 每个男生的期望值
bool vis_girl[MAXN];    // 记录每一轮匹配匹配过的女生
bool vis_boy[MAXN];     // 记录每一轮匹配匹配过的男生
int match[MAXN];        // 记录每个男生匹配到的妹子 如果没有则为-1
int slack[MAXN];        // 记录每个汉子如果能被妹子倾心最少还需要多少期望值

int N,M;


bool dfs(int girl)
{
    vis_girl[girl] = true;

    for (int boy = 0; boy < M; ++boy) {

        if (vis_boy[boy]) continue; // 每一轮匹配 每个男生只尝试一次

        int gap = ex_girl[girl] + ex_boy[boy] - love[girl][boy];
        if (gap == 0) {  // 如果符合要求
            vis_boy[boy] = true; 
            if (match[boy] == -1 || dfs( match[boy] )) {    // 找到一个没有匹配的男生 或者该男生的妹子可以找到其他人
                match[boy] = girl;
                return true;
            }
        } else {
            slack[boy] = min(slack[boy], gap);  // slack 可以理解为该男生要得到女生的倾心 还需多少期望值 取最小值 备胎的样子【捂脸
        }
    }

    return false;
}

int KM()
{
    memset(match, -1, sizeof match);    // 初始每个男生都没有匹配的女生
    memset(ex_boy, 0, sizeof ex_boy);   // 初始每个男生的期望值为0
    memset(ex_girl,0,sizeof(ex_girl));  
    //1:将初始女生期望值设成0而不是第一个期望值,因为这个女生可能没有匹配
    //2:我们要设成比所有正数小的数,但是不可以设成-INF。如果设成-INF,在没有匹配时,会和所有男生形成匹配(因为没有匹配,好感度我们初始设成-INF)
    //3:这样,没有匹配的情况下,我们dfs时,男生与女生期望值均为0,好感度INF,slack(距离好感度)就为INF;  
    // 每个女生的初始期望值是与她相连的男生最大的好感度
    for (int i = 0; i < N; ++i) {
        for (int j = 0; j < M; ++j) {
            ex_girl[i] = max(ex_girl[i], love[i][j]);
        }
    }

    // 尝试为每一个女生解决归宿问题
    for (int i = 0; i < N; ++i) {

        memset (slack, INF, sizeof(slack));    // 因为要取最小值 初始化为无穷大

        while (1) {
            // 为每个女生解决归宿问题的方法是 :如果找不到就降低期望值,直到找到为止

            // 记录每轮匹配中男生女生是否被尝试匹配过
            memset(vis_girl, false, sizeof vis_girl);
            memset(vis_boy, false, sizeof vis_boy);

            if (dfs(i)) break;  // 找到归宿 退出

            // 如果不能找到 就降低期望值
            // 最小可降低的期望值
            int d = INF;
            for (int j = 0; j < M; ++j)
                if (!vis_boy[j]) d = min(d, slack[j]);
  //        如果一个都没有匹配 ,d就会是INF,跳出 
            if(d==INF) return -1;
            
            for (int j = 0; j < N; ++j) {
                // 所有访问过的女生降低期望值
                if (vis_girl[j]) ex_girl[j] -= d;
            }
            for(int j=0;j<M;j++){
                // 所有访问过的男生增加期望值
                if (vis_boy[j]) ex_boy[j] += d;
                // 没有访问过的boy 因为girl们的期望值降低,距离得到女生倾心又进了一步!
                else slack[j] -= d;
                            
            }

        }
    }
    // 匹配完成 求出所有配对的好感度的和
    int res = 0;
    int ct=0;
    for (int i = 0; i < M; ++i){
           if(match[i]!=-1){
            res += love[ match[i] ][i];
            ct++;
        }        
    }
    if(ct!=N) return -1;    
    return res;
}

int main()
{
    int e;
    int count=1;
    int ren,fz,v;
    while (~scanf("%d%d", &N,&M)) {
        scanf("%d",&e);
    fill(love[0], love[0] + MAXN * MAXN, -INF);//不能匹配的初始化为-INF 
        while(e--){
            
            scanf("%d%d%d",&ren,&fz,&v);
            if(v<0) continue;//负数不能匹配,直接设为-INF; 
            love[ren][fz]=v;
        }
        printf("Case %d: %d\n",count++, KM());
    }
    return 0;
}        

原文地址:https://www.cnblogs.com/ellery/p/11725707.html