下列代码是二分图的最佳匹配问题,即权值最大的匹配,网上找了一些代码,有些小问题,修改了下,下面这份代码是修改后的:
#include<algorithm>
using namespace std;
const int MAXN = 305;
const int INF = 0x3f3f3f3f;
int disMat[MAXN][MAXN]; //特征矩阵
int ex_a[MAXN]; //a的期望
int ex_b[MAXN]; //b的期望
bool vis_a[MAXN]; //记录每一轮匹配过的a
bool vis_b[MAXN]; //记录每一轮匹配过的b
int match[MAXN]; //记录每个b匹配到的a 如果没有则为-1
int slack[MAXN]; //记录每个b如果能被a匹配到最少还需要多少期望值
int aN, bN;
bool dfs(int a)
{
vis_a[a] = true;
for (int b = 0; b < bN; ++b)
{
if (vis_b[b])// 每一轮匹配 每个b只尝试一次
continue;
int gap = ex_a[a] + ex_b[b] - disMat[a][b];
if (gap == 0) //如果符合要求
{
vis_b[b] = true;
if (match[b] == -1 || dfs(match[b])) // 找到一个没有匹配的b 或者该b的a可以找到其他a
{
match[b] = a;
return true;
}
}
else
{
slack[b] = min(slack[b], gap); /// slack 该b要得到一个a的匹配 还需多少期望值
}
}
return false;
}
int KM()
{
int bNori = bN;
//特征矩阵对于bN<aN的情况缺值补0 因为所有a一定需要匹配一个b 不然跳不出循环
if (bN < aN)
{
for (int j = bN; j < aN; ++j)
{
for (int i = 0; i < aN; ++i)
{
disMat[i][j] = 0;
}
}
bN = aN;
}
memset(match, -1, sizeof(match)); // 初始每个b都没有匹配的a memset的单位是char 但是对于非char型 仅对-1和0的赋值有效 这属于魔术编程 不清楚的话最好别这么用
memset(ex_b, 0, sizeof(ex_b)); //初始每个b的期望值为0
// 每个a的初始期望值是与它有匹配关系的b的最大的特征值
for (int i = 0; i < aN; ++i)
{
ex_a[i] = disMat[i][0];
for (int j = 1; j < bN; ++j)
{
ex_a[i] = max(ex_a[i], disMat[i][j]);
}
}
// 尝试为每一个a做匹配
for (int i = 0; i < aN; ++i)
{
// 因为要取最小值 初始化为无穷大
// tips: 这里的slack要赋的值不是0或-1 所以不能再用memset赋了 要写for循环
for (int j = 0; j < MAXN; ++j)
{
slack[j] = INF;
}
// 为每个a解决匹配的方法是 :如果找不到就降低期望值 直到找到或者期望值降到0为止
while (1)
{
// 记录每轮匹配中a和b是否被尝试匹配过
memset(vis_a, false, sizeof vis_a);
memset(vis_b, false, sizeof vis_b);
if (dfs(i)) // 找到匹配 退出
break;
// 如果不能找到 就降低期望值
// 最小可降低的期望值
int d = INF;
for (int j = 0; j < bN; ++j)
{
if (!vis_b[j])
d = min(d, slack[j]);
}
for (int j = 0; j < aN; ++j)
{
// 所有访问过的a降低期望值
if (vis_a[j])
ex_a[j] -= d;
}
for (int j = 0; j < bN; ++j)
{
// 所有访问过的b增加期望值
if (vis_b[j])
ex_b[j] += d;
// 没有访问过的b 降低a的期望值
else
slack[j] -= d;
}
}
}
// 匹配完成 查看匹配
int res = 0;
for (int j = 0; j < bNori; ++j)
{
int aIdx = match[j];
int bIdx = j;
if (disMat[aIdx][bIdx] > 0)
{
printf("a: %d b: %d\n", aIdx, bIdx);
res += disMat[aIdx][j];
}
}
return res;
}
int main()
{
aN = 4;
bN = 3;
disMat[0][0] = 3;
disMat[0][1] = 0;
disMat[1][1] = 2;
disMat[2][0] = 4;
int res = KM();
printf("total wei: %d\n",res);
return 0;
}