1. 程式人生 > >Interesting Housing Problem(HDU-2426)

Interesting Housing Problem(HDU-2426)

Problem Description

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?

Input

There 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, Si, Ri, Vi, (0 <= Si < N, 0 <= Ri < M, |Vi| <= 10000), describing the rating Vi given by student Si for room Ri. 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.

Output

For 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

————————————————————————————————————————————————————

題意:有 n 個學生 m 個房間 e 組打分,每組打分代表學生 x 對房間 y 打分 w,如果分數大於等於 0,表示他可能會選擇這個房間,如果一個房間分數小於 0 或者沒打過分,則不能選擇,現在問是否存在一個匹配,使得每個學生分得一個房間,每個房間最多一個學生,並且這些房間都是學生打過分且分數大於 0 的房間,若存在,則輸出分數和的最大值,若不存在,輸出 -1

思路:首先,當學生數大於房間數時,直接輸出 -1,然後選取學生為左點集房間為右點集,對學生 i 打過分的房間 j 建一條邊,邊的權值是學生打的分數,若對一個房間,某學生打的分數小於 0 或者其為對這個房間打過分,則設這條邊的權值為負無窮,那麼當求最優匹配的時候,總權值即為最優匹配的權值解,若存在某條邊的權值是負無窮,則說明問題無解

Source Program

#include<iostream>
#include<cstdio>
#include<cstdlib>
#include<string>
#include<cstring>
#include<cmath>
#include<ctime>
#include<algorithm>
#include<stack>
#include<queue>
#include<vector>
#include<set>
#include<map>
#define PI acos(-1.0)
#define E 1e-6
#define MOD 16007
#define INF 0x3f3f3f3f
#define N 1001
#define LL long long
using namespace std;
int n,m;
int G[N][N];
int Lx[N],Ly[N];
bool visX[N],visY[N];
int linkX[N],linkY[N];
bool dfs(int x){
    visX[x]=true;
    for(int y=1;y<=m;y++){
        if(!visY[y]){
            int temp=Lx[x]+Ly[y]-G[x][y];
            if(temp==0){
                visY[y]=true;
                if(linkY[y]==-1 || dfs(linkY[y])){
                    linkX[x]=y;
                    linkY[y]=x;
                    return true;
                }
            }
        }
    }
    return false;
}
void update(){
    int minn=INF;
    for(int i=1;i<=n;i++)
        if(visX[i])
            for(int j=1;j<=m;j++)
                if(!visY[j])
                    minn=min(minn,Lx[i]+Ly[j]-G[i][j]);

    for(int i=1;i<=n;i++)
        if(visX[i])
            Lx[i]-=minn;

    for(int i=1;i<=m;i++)
        if(visY[i])
            Ly[i]+=minn;
}
int KM(){
    memset(linkX,-1,sizeof(linkX));
    memset(linkY,-1,sizeof(linkY));

    memset(Lx,0,sizeof(Lx));
    memset(Ly,0,sizeof(Ly));
    for(int i=1;i<=n;i++)
        for(int j=1;j<=m;j++)
            Lx[i]=max(Lx[i],G[i][j]);

    for(int i=1;i<=n;i++){
        while(true){
            memset(visX,false,sizeof(visX));
            memset(visY,false,sizeof(visY));

            if(dfs(i))
                break;
            else
                update();
        }
    }

    int ans=0;
    for(int i=1;i<=m;i++){
        if(linkY[i]!=-1){
            if(G[linkY[i]][i]!=-INF)
                ans+=G[linkY[i]][i];
            else
                ans=-1;
        }
    }
    return ans;
}
int main(){
    int e;
    int Case=1;
    while(scanf("%d%d%d",&n,&m,&e)!=EOF&&(n+m+e)){
        if(n>m)
            printf("Case %d: %d\n",Case++,-1);
        else{
            for(int i=1;i<=n;i++)
                for(int j=1;j<=m;j++)
                    G[i][j]=-INF;

            while(e--){
                int x,y,w;
                scanf("%d%d%d",&x,&y,&w);
                x++,y++;
                if(w>=0)
                    G[x][y]=w;
            }

            printf("Case %d: %d\n",Case++,KM());
        }
    }
    return 0;
}