在计算机科学和运筹学中,KM算法(Kuhn-Munkres Algorithm),也被称为匈牙利算法的加权版本,是解决二分图最大权完美匹配问题的经典方法。本文将用通俗易懂的方式,手把手教你如何用C语言实现KM算法,即使你是编程小白也能轻松理解!
想象你有两组人:一组是工人,另一组是任务。每个工人完成不同任务能获得不同的收益(权重)。我们的目标是给每个工人分配一个唯一的任务,使得总收益最大。这就是二分图最大权完美匹配问题。

KM算法通过维护两个顶标(label)数组 lx[] 和 ly[],使得对于任意边 (i, j),都有 lx[i] + ly[j] >= weight[i][j]。算法不断调整顶标,直到找到一个完美匹配,且所有匹配边都满足 lx[i] + ly[j] == weight[i][j],此时总权值最大。
下面我们将逐步实现KM算法。假设我们有一个 n×n 的权值矩阵 w[][],表示二分图左右两边各 n 个节点之间的权重。
#include <stdio.h>#include <string.h>#include <limits.h>#define MAXN 105 // 最大节点数#define INF INT_MAXint n; // 节点数量int w[MAXN][MAXN]; // 权值矩阵int lx[MAXN], ly[MAXN]; // 左右顶标int match[MAXN]; // 右侧节点匹配的左侧节点bool vx[MAXN], vy[MAXN]; // 访问标记int slack[MAXN]; // slack数组用于优化bool dfs(int u) { vx[u] = true; for (int v = 0; v < n; v++) { if (vy[v]) continue; int t = lx[u] + ly[v] - w[u][v]; if (t == 0) { vy[v] = true; if (match[v] == -1 || dfs(match[v])) { match[v] = u; return true; } } else if (slack[v] > t) { slack[v] = t; } } return false;}int KM() { // 初始化顶标 memset(ly, 0, sizeof(ly)); for (int i = 0; i < n; i++) { lx[i] = -INF; for (int j = 0; j < n; j++) { if (w[i][j] > lx[i]) lx[i] = w[i][j]; } } // 初始化匹配 memset(match, -1, sizeof(match)); for (int i = 0; i < n; i++) { while (true) { memset(vx, false, sizeof(vx)); memset(vy, false, sizeof(vy)); for (int j = 0; j < n; j++) slack[j] = INF; if (dfs(i)) break; // 更新顶标 int d = INF; for (int j = 0; j < n; j++) if (!vy[j] && slack[j] < d) d = slack[j]; for (int j = 0; j < n; j++) { if (vx[j]) lx[j] -= d; if (vy[j]) ly[j] += d; else slack[j] -= d; } } } // 计算最大权值和 int result = 0; for (int i = 0; i < n; i++) result += w[match[i]][i]; return result;}int main() { // 示例:3x3 权值矩阵 n = 3; int weights[3][3] = { {3, 2, 4}, {1, 5, 2}, {2, 1, 3} }; for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) w[i][j] = weights[i][j]; int maxWeight = KM(); printf("最大权匹配值为: %d\n", maxWeight); // 输出匹配结果 for (int j = 0; j < n; j++) printf("左节点 %d 匹配右节点 %d\n", match[j], j); return 0;}- 时间复杂度:朴素KM算法为 O(n⁴),但通过使用 slack 数组可优化至 O(n³)。
- 适用范围:仅适用于完全二分图(即左右节点数相等且存在完美匹配)。
- 负权处理:若存在负权,需先对权值整体偏移使其非负。
通过本教程,你应该已经掌握了KM算法的基本原理和C语言实现方法。无论是解决实际分配问题,还是应对算法竞赛,这套代码都能为你提供坚实基础。记住,理解二分图最大权匹配的核心在于顶标的维护与调整,而匈牙利算法优化的思想贯穿始终。
提示:建议将上述代码保存为 km_algorithm.c 并使用 GCC 编译运行,观察输出结果加深理解。
本文由主机测评网于2025-12-17发表在主机测评网_免费VPS_免费云服务器_免费独立服务器,如有疑问,请联系我们。
本文链接:https://www.vpshk.cn/2025129019.html