Problem Description 传说在遥远的地方有一个非常富裕的村落,有一天,村长决定进行制度改革:重新分配房子。
Input 输入数据包含多组测试用例,每组数据的第一行输入n,表示房子的数量(也是老百姓家的数量),接下来有n行,每行n个数表示第i个村名对第j间房出的价格(n<=300)。
Output 请对每组数据输出最大的收入值,每组的输出占一行。
Sample Input 2 100 10 15 23 |
在代码中标记很清楚,可以看;
如果不懂KM算法,可以看这篇博客,大佬写的很详细;
#include<stdio.h>
#include<string.h>
#include<string>
#include<algorithm>
#include<iostream>
#include<math.h>
#define inf 0x3f3f3f3f
using namespace std;
const int N=305;
int e[N][N]; //记录权值
int la[N]; //记录人的期望值(能配对的最大值)
int lb[N]; //记录房子的期望值
int visa[N]; //标记每次搜索参与匹配的人
int visb[N]; //标记每次搜索参与匹配的房子
int match[N]; //记录房子匹配到的人,没有匹配标记-1
int slack[N]; //记录每个房子如果能被人倾心最少还需要多少期望值
int n;
int dfs(int a)
{
visa[a]=1;
int i,j;
for(i=1; i<=n; i++)
{
if(visb[i])//每次匹配只用一次
continue;
int temp=la[a]+lb[i]-e[a][i];
if(temp==0)
{
visb[i]=1;
if(match[i]==-1||dfs(match[i]))//如果找到没有匹配的房子或者匹配该房子的人能找到另一个房子
{
match[i]=a;
return true;
}
}
else
slack[i]=min(slack[i],temp);
}
return false;
}
int KM()
{
memset(lb,0,sizeof(lb));
memset(match,-1,sizeof(match));
int i,j;
for(i=1; i<=n; i++)
{
la[i]=e[i][1];
for(j=2; j<=n; j++)
la[i]=max(la[i],e[i][j]);
}
for(i=1; i<=n; i++)
{
fill(slack+1,slack+1+n,inf);
while(1)
{
memset(visa,0,sizeof(visa));
memset(visb,0,sizeof(visb));
int d=inf;
if(dfs(i))//匹配到就退出
break;
// 如果不能找到 就降低期望值
// 最小可降低的期望值
for(j=1; j<=n; j++)
if(!visb[j])
d=min(d,slack[j]);
for(j=1; j<=n; j++)
{
if(visa[j]) la[j]-=d;
if(visb[j]) lb[j]+=d;
else slack[j]-=d;
}
}
}
int ans=0;
for(i=1; i<=n; i++)
ans+=e[match[i]][i];
return ans;
}
int main()
{
while(~scanf("%d",&n))
{
int i,j;
for(i=1; i<=n; i++)
for(j=1; j<=n; j++)
scanf("%d",&e[i][j]);
printf("%d\n",KM());
}
return 0;
}