题意:有 n 个学生,m 个房间,给定 e 个三元组 表示学生
对 房间
的喜爱度为
,现在要求给每一个学生匹配一个房间(每个房间至多只能容纳一名学生)使得总喜爱度最大,要求给每个学生分配的房间的喜爱度必须大于等于0;
分析:n>m 肯定无解,因为不能给每个学生都分配唯一的房间;对于喜爱度为负和没有喜爱度的房间,一律设为负无穷(等价于不能选),然后用 KM 求最大权匹配,最后统计的时候若出现负权匹配则证明无解;
int res=0;
for(int i=0;i<nn;i++)
{
if(love[i][ans[i]]<0) return -1; //出现负权,无解
res+=love[i][ans[i]];
}
return res;
代码:
#include<cmath>
#include<cstdio>
#include<cstring>
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 500+5;
const int INF = 0x3f3f3f3f;
char mp[N][N];
struct node
{
int x,y;
}man[N],hor[N];
int love[N][N];
int ex_girl[N];
int ex_boy[N];
bool vis_girl[N];
bool vis_boy[N];
int match[N];
int ans[N];
int slack[N];
int n,m,e,nn;
bool dfs(int girl)
{
vis_girl[girl]=true;
for(int boy=0;boy<n;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;
ans[girl]=boy;
return true;
}
}
else
slack[boy]=min(slack[boy],gap);
}
return false;
}
int KM()
{
memset(match,-1,sizeof(match));
memset(ans,-1,sizeof(ans));
memset(ex_boy,0,sizeof(ex_boy));
for(int i=0;i<n;i++)
{
ex_girl[i]=love[i][0];
for(int j=0;j<n;j++)
ex_girl[i]=max(love[i][j],ex_girl[i]);
}
for(int i=0;i<n;i++)
{
fill(slack,slack+n,INF);
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<n;j++)
if(!vis_boy[j])
d=min(d,slack[j]);
for(int j=0;j<n;j++)
{
if(vis_girl[j])
ex_girl[j]-=d;
if(vis_boy[j])
ex_boy[j]+=d;
else
slack[j]-=d;
}
}
}
int res=0;
for(int i=0;i<nn;i++)
{
if(love[i][ans[i]]<0) return -1;
res+=love[i][ans[i]];
}
return res;
}
int main()
{
int cas=0;
while(~scanf("%d%d%d",&n,&m,&e))
{
nn=n;
n=max(n,m);
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
love[i][j]=-INF;
int s,r,v;
while(e--)
{
scanf("%d%d%d",&s,&r,&v);
if(v>=0)love[s][r]=max(v,love[s][r]);
}
int ans;
if(nn>m) ans=-1;
else ans=KM();
printf("Case %d: %d\n",++cas,ans);
}
}