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();
}
}