题意:给出房子和买家的数量都为n,还有不同房子买家愿意出的钱(以矩阵形式给出)
题解:直接输入到mp[i][j],跑一遍KM算法即可~时间复杂度为O(n^3).
代码如下:
#include<iostream>
#include<cstring>
#include<string>
#include<cstdio>
#include<cmath>
#include<vector>
#include<queue>
#include<map>
#include<algorithm>
using namespace std;
#define ll long long
#define inf 0x3f3f3f3f
const int maxn = 310;
int link[maxn], lx[maxn], ly[maxn], slack[maxn]; //lx,ly分别为x点集y点集的个数
int visx[maxn], visy[maxn], mp[maxn][maxn];
int n;
int dfs(int x) {
visx[x] = 1;
for (int y = 1; y <= n; y++) {
if (visy[y]) continue;
int t = lx[x] + ly[y] - mp[x][y];
if (t == 0) {
visy[y] = 1;
if (link[y] == -1 || dfs(link[y])) {
link[y] = x;
return 1;
}
}
else if (slack[y] > t)//不在相等子图中stack取最小的
slack[y] = t;
}
return 0;
}
int km() {
int i, j;
memset(link, -1, sizeof(link));
memset(ly, 0, sizeof(ly));
for (i = 1; i <= n; i++) //lx初始化为与它关联变中最大的
for (j = 1, lx[i] = -inf; j <= n; j++)
if (mp[i][j] > lx[i]) lx[i] = mp[i][j];
for (int x = 1; x <= n; x++) {
memset(slack, inf, sizeof(slack));
while (1) {
memset(visx, 0, sizeof(visx));
memset(visy, 0, sizeof(visy));
if (dfs(x)) //若成功,则该点增广路完成,进入下一个点的增广
break;
//若失败。则需要改变一些点的标号,使得图中可行边的数量增加
//方法:将所有的增广路中的x方的点的标号全部减去一个常数d
// 所有在增广路中的y方的点标号全部加上一个常数d
int d = inf;
for (int i = 1; i <= n; i++)
if (!visy[i] && d > slack[i])
d = slack[i];
for (i = 1; i <= n; i++)
if (visx[i])
lx[i] -= d;
for (i = 1; i <= n; i++)//修改顶标后,要把所有不在交错树中的y顶点的slack值都减去d
if (visy[i])
ly[i] += d;
else
slack[i] -= d;
}
}
int res = 0;
for (i = 1; i <= n; i++)
if (link[i] > -1)
res += mp[link[i]][i];
return res;
}
int main() {
while (~scanf("%d", &n)) {
for (int i = 1; i <= n; i++)for (int j = 1; j <= n; j++)scanf("%d", &mp[i][j]);
printf("%d\n", km());
}
return 0;
}