HDU 2426 Interesting Housing Problem (最大权完美匹配)【KM】

<题目链接>

题目大意:

学校里有n个学生和m个公寓房间,每个学生对一些房间有一些打分,如果分数为正,说明学生喜欢这个房间,若为0,对这个房间保持中立,若为负,则不喜欢这个房间。学生不会住进不喜欢的房间和没有打分的房间。问安排这n个学生来求最大的分数,如果不能够使这些学生全部入住房间,就输出-1,每个房间最多只能住一个学生。

解题分析:

因为需要求带权二分图,所以用KM算法,需要注意的是,边权为负的两点不能进行匹配,并且,最后需要判断是否符合题意,即是否所有学生都有房间。

 1 #include <cstring>
 2 #include <cstdio>
 3 #include <algorithm>
 4 using namespace std;
 5 
 6 const int N = 505;
 7 #define INF 0x3f3f3f3f
 8 #define CLR(a,b) memset(a,b,sizeof(a))
 9 #define rep(i,s,t) for(int i=s;i<t;i++)
10 
11 int nx,ny,k;
12 int w[N][N],linker[N],visx[N],visy[N],lx[N],ly[N],slack[N];
13 bool DFS(int x){
14     visx[x]=1;
15     rep(y,0,ny){
16         if(!visy[y]&&w[x][y]>=0){    //如果w[x][y]<0,就不能匹配
17             int tmp=lx[x]+ly[y]-w[x][y];
18             if(tmp==0){
19                 visy[y]=1;
20                 if(linker[y]==-1||DFS(linker[y])){
21                     linker[y]=x;
22                     return true;
23                 }
24             }else slack[y]=min(slack[y],tmp);
25         }
26     }
27     return false;
28 }
29 int KM(){    
30     CLR(linker,-1);CLR(ly,0);
31     rep(i,0,nx){
32         lx[i]=-INF;
33         rep(j,0,ny){
34             lx[i]=max(lx[i],w[i][j]);
35         }
36         if(lx[i]<0)return -1;    //在取完最值后,lx[i]仍然<0,说明该人不想住进任何一间房子,所以直接返回-1即可
37     }
38     rep(x,0,nx){
39         rep(i,0,ny)slack[i]=INF;
40         while(true){
41             CLR(visx,0);CLR(visy,0);
42             if(DFS(x))break;
43             int d=INF;
44             rep(i,0,ny)if(!visy[i])d=min(d,slack[i]);
45             rep(i,0,nx)if(visx[i])lx[i]-=d;
46             rep(i,0,ny)
47                 if(visy[i])ly[i]+=d;
48                 else slack[i]-=d;
49         }
50     }
51     int res=0,count=0;
52     rep(y,0,ny){
53         if(linker[y]!=-1)res+=w[linker[y]][y],count++;    //count记录有房子住的人数 
54     }
55     if(count<nx)return -1;
56     return res;
57 }
58 int main(){
59     int ncase=0;
60     while(~scanf("%d%d%d",&nx,&ny,&k)){
61         CLR(w,-1);
62         rep(i,0,k){
63             int a,b,c;scanf("%d%d%d",&a,&b,&c);
64             w[a][b]=c;
65         }
66         printf("Case %d: %d\n",++ncase,KM());
67     }
68 }

2018-11-18

猜你喜欢

转载自www.cnblogs.com/00isok/p/9979673.html