hdu 2426 Interesting Housing Problem【KM】

Interesting Housing Problem

Time Limit: 10000/2000 MS (Java/Others)    Memory Limit: 32768/32768 K (Java/Others)
Total Submission(s): 3043    Accepted Submission(s): 1094

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

Source

2008 Asia Hangzhou Regional Contest Online

 

题目大意:

有n个人,m个公寓,每个人需要入住一个公寓,并且每个公寓只能入住一个人,对应这n个人对这m个公寓会有k个评价,对应每个评价三个元素,表示人的编号,公寓的编号,以及对应打出的评分,其值如果大于0,表示喜欢这个公寓,如果等于0表示不喜欢也不讨厌,可以入住,如果小于0,表示讨厌这个公寓,不能入住。而且每个人都不能入住自己没有对公寓评价过的公寓。问能否找到一个合理的分配使得每个人对应喜欢的值累加和最高。如果可以输出,否则输出-1.


思路:


1、不难想到,将人看成左集合,将公寓看成右集合,显然一个二分图,每个人只能匹配一个公寓并且相应有权值,那么就是一个最大权匹配问题。


2、首先n>m是一定无解的。


3、那么初始化图的每一条边都是 -inf,在匹配过程中是一定不会首选这种边的,如果选择了,其实就是输出-1的情况(对应没有做过评价的边,或者是负权值的边,都是不可行的分配方式),其余情况直接跑KM输出最优解即可。


Ac代码(但是跑的好慢,第一次提交TLE,第二次提交1700+ms AC):

#include<stdio.h>
#include<string.h>
#include<iostream>
using namespace std;
int lx[650];
int ly[650];
int match[650];
int vx[650];
int vy[650];
int a[650][650];
int n,m,q,low;
int find(int u)
{
    vx[u]=1;
    for(int j=0;j<m;j++)
    {
        if(vy[j]==1)continue;
        int tmpp=lx[u]+ly[j]-a[u][j];
        if(tmpp==0)
        {
            vy[j]=1;
            if(match[j]==-1||find(match[j]))
            {
                match[j]=u;
                return 1;
            }
        }
        else if(tmpp<low)low=tmpp;
    }
    return 0;
}
void KM()
{
    memset(match,-1,sizeof(match));
    memset(lx,0,sizeof(lx));
    memset(ly,0,sizeof(ly));
    for(int i=0;i<n;i++)
    {
        for(int j=0;j<m;j++)
        {
            lx[i]=max(lx[i],a[i][j]);
        }
    }
    for(int i=0;i<n;i++)
    {
        while(1)
        {
            memset(vx,0,sizeof(vx));
            memset(vy,0,sizeof(vy));
            low=0x3f3f3f3f;
            if(find(i))break;
            for(int j=0;j<n;j++)
            {
                if(vx[j])lx[j]-=low;
            }
            for(int j=0;j<m;j++)
            {
                if(vy[j])ly[j]+=low;
            }
        }
    }
    int sum=0;
    int flag=0;
    for(int i=0;i<m;i++)
    {
        if(match[i]==-1)continue;
        if(a[match[i]][i]==-0x3f3f3f3f)flag=1;
        sum+=a[match[i]][i];
    }
    if(flag==0)
    printf("%d\n",sum);
    else printf("-1\n");
}
int main()
{
    int kase=0;
    while(~scanf("%d%d%d",&n,&m,&q))
    {
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                a[i][j]=-0x3f3f3f3f;
            }
        }
        for(int i=0;i<q;i++)
        {
            int x,y,w;
            scanf("%d%d%d",&x,&y,&w);
            if(w<0)continue;
            if(a[x][y]<w)
            {
                a[x][y]=w;
            }
        }
        printf("Case %d: ",++kase);
        if(n>m)
        {
            printf("-1\n");
            continue;
        }
        KM();
    }
}





  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 2
    评论
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值