#include <iostream>
#include <vector>
#include <cmath>
#include <algorithm>
using namespace std;
#ifndef UNMATCHEDFLAG
#define UNMATCHEDFLAG -1
#endif
int dcmp(double a, double b) {
double epsilon = 1e-6;
double diff = fabs(a - b);
if (diff <= epsilon) {
return 0;
} else if (a < b) {
return -1;
} else {
return 1;
}
}
bool dfs(vector<vector<double>> &matrix, int leftIndex, vector<bool> &visitedA, vector<bool> &visitedB, vector<int> &matched, vector<double> &delta, vector<double> &leftValue, vector<double> &rightValue) {
visitedA[leftIndex] = true;
cout << "left " << leftIndex << endl;
for (int y = 0; y < matrix[0].size(); y++) {
if (!visitedB[y]) {
cout << " leftValue " << leftValue[leftIndex] << " rightValue[y] "<< rightValue[y] << " matrix " << matrix[leftIndex][y] << endl;
if (0 == dcmp(leftValue[leftIndex] + rightValue[y] ,matrix[leftIndex][y])) {
cout << "y " << y << " matched[y] "<< matched[y] <<endl;
visitedB[y] = true;
if (UNMATCHEDFLAG == matched[y] || dfs(matrix, matched[y], visitedA, visitedB, matched, delta, leftValue, rightValue)) {
matched[y] = leftIndex;
return true;
}
} else {
delta[y] = std::min(leftValue[leftIndex] + rightValue[y] - matrix[leftIndex][y], delta[y]);
cout << "y " << y << " delta[y] "<< delta[y] <<endl;
}
}
}
return false;
}
/**
* @brief 获取matrix的最大匈牙利匹配,将匹配结果放入res
*
* @param matrix 传入的二维矩阵,每个节点表示左右结点的权重,当维度不一致时需要自行填充最小值使其维度匹配
* @param matchedRes 返回匹配结果的行下标,即matrix列匹配的每一行的下标
* @return double 返回匹配的最大值
*/
double hungarian(vector<vector<double>> &matrix, vector<int> &matchedRes) {
if (0 == matrix.size() || matrix.size() != matrix[0].size()) {
return 0;
}
double maxValue;
double maxDoubleValue = std::numeric_limits<double>::max();
vector<bool> visitedA(matrix[0].size(), false); // 左侧是否在交替路中
vector<bool> visitedB(matrix[0].size(), false); // 右侧是否在交替路中
vector<int> matched(matrix[0].size(), UNMATCHEDFLAG); // 匹配结果
vector<double> delta(matrix[0].size(), maxDoubleValue); // 左右顶标差值
vector<double> leftValue(matrix.size(), 0); // 左顶标的值
vector<double> rightValue(matrix[0].size(), 0); // 右顶标的值
for(size_t i = 0; i < matrix.size(); i++) {
leftValue[i] = *std::max_element(matrix[i].begin(), matrix[i].end());
}
for(size_t i = 0; i < matrix.size(); i++) {
while(true) {
fill(visitedA.begin(), visitedA.end(), false);
fill(visitedB.begin(), visitedB.end(), false);
fill(delta.begin(), delta.end(), maxDoubleValue);
if (dfs(matrix, i, visitedA, visitedB, matched, delta, leftValue, rightValue)) {
break;
}
double minus = maxDoubleValue;
// 处理顶标值,左侧增广路径顶标减去delta, 右侧则加上delta
for (size_t j = 0; j < delta.size(); j++) {
if (!visitedB[j]) {
minus = std::min(minus, delta[j]);
}
}
cout << "minus " << minus << endl;
for (int i = 0; i < matrix.size(); i++) {
if (visitedA[i]) {
leftValue[i] -= minus;
}
if (visitedB[i]) {
rightValue[i] += minus;
}
cout << "left " << leftValue[i] << " RIGHT " << rightValue[i] << endl;
}
}
}
for (int i = 0; i < matrix.size(); i++) {
maxValue += matrix[matched[i]][i];
matchedRes.push_back(matched[i]);
}
return maxValue;
}
int main(void) {
double minDoubleValue = std::numeric_limits<double>::min();
vector<vector<double>> matrix = {{1, 2, minDoubleValue }, {minDoubleValue , 7, 3}, {8, minDoubleValue , 1}};
vector<int> assignment;
int value;
value = hungarian(matrix, assignment);
cout << matrix.size() << endl;
for(int i = 0; i < matrix.size(); i++) {
cout << i << " " << assignment[i] << endl;
}
cout << value<< endl;
return 0;
}
匈牙利最大匹配算法代码(KM算法) 权重为double类型 代码实现
于 2024-01-23 11:38:06 首次发布