MATLAB实现匈牙利算法求解二分图最大匹配
匈牙利算法(也称为Kuhn-Munkres算法)是解决二分图最大匹配问题的经典算法。
代码
function [matching, max_match] = hungarian_algorithm(adjMatrix)
% HUNGARIAN_ALGORITHM 实现匈牙利算法求解二分图最大匹配
% 输入:
% adjMatrix - 二分图的邻接矩阵,大小为m×n,m表示左侧顶点数,n表示右侧顶点数
% 输出:
% matching - 匹配结果向量,matching(i)表示左侧第i个顶点匹配的右侧顶点索引(0表示未匹配)
% max_match - 最大匹配数
[m, n] = size(adjMatrix);
% 初始化匹配数组:matching_left表示左侧顶点的匹配,matching_right表示右侧顶点的匹配
matching_left = zeros(1, m); % 左侧匹配结果,初始为0(未匹配)
matching_right = zeros(1, n); % 右侧匹配结果,初始为0(未匹配)
% 定义DFS函数用于寻找增广路径
function found = dfs(u, visited)
for v = 1:n
% 如果存在边且右侧顶点v未被访问
if adjMatrix(u, v) && ~visited(v)
visited(v) = true; % 标记右侧顶点v为已访问
% 如果右侧顶点v未被匹配,或者已匹配的左侧顶点可以找到其他匹配
if matching_right(v) == 0 || dfs(matching_right(v), visited)
matching_left(u) = v; % 将左侧u匹配到右侧v
matching_right(v) = u; % 将右侧v匹配到左侧u
found = true; % 找到增广路径
return;
end
end
end
found = false; % 未找到增广路径
end
% 主算法:对每个左侧顶点尝试寻找匹配
for u = 1:m
visited = false(1, n); % 初始化访问标记数组
dfs(u, visited); % 尝试为当前左侧顶点u寻找匹配
end
% 统计匹配数
max_match = sum(matching_left > 0);
% 返回左侧匹配结果
matching = matching_left;
end
算法测试与示例
1:简单二分图
% 创建邻接矩阵 (3x3)
adjMatrix = [
1, 0, 1; % 左侧顶点1连接右侧顶点1和3
0, 1, 0; % 左侧顶点2连接右侧顶点2
1, 1, 0; % 左侧顶点3连接右侧顶点1和2
];
% 运行匈牙利算法
[matching, max_match] = hungarian_algorithm(adjMatrix);
% 显示结果
disp('匹配结果:');
for i = 1:length(matching)
if matching(i) > 0
fprintf('左侧顶点 %d 匹配到右侧顶点 %d\n', i, matching(i));
else
fprintf('左侧顶点 %d 未匹配\n', i);
end
end
fprintf('最大匹配数: %d\n', max_match);
2:更大规模的二分图
% 创建随机二分图 (10x8)
rng(42); % 设置随机种子确保可重复性
adjMatrix = randi([0, 1], 10, 8); % 随机生成0-1矩阵
% 运行匈牙利算法
[matching, max_match] = hungarian_algorithm(adjMatrix);
% 显示结果
disp('邻接矩阵:');
disp(adjMatrix);
disp('匹配结果:');
disp(matching);
fprintf('最大匹配数: %d\n', max_match);
% 可视化结果
figure;
hold on;
title('二分图匹配结果');
xlim([0, 3]);
ylim([0, max(10, 8)+1]);
% 绘制左侧顶点
for i = 1:10
plot(0.5, i, 'bo', 'MarkerSize', 10, 'MarkerFaceColor', 'b');
text(0.4, i, sprintf('L%d', i));
end
% 绘制右侧顶点
for j = 1:8
plot(2.5, j, 'ro', 'MarkerSize', 10, 'MarkerFaceColor', 'r');
text(2.6, j, sprintf('R%d', j));
end
% 绘制所有边
for i = 1:10
for j = 1:8
if adjMatrix(i, j)
plot([0.5, 2.5], [i, j], 'k:', 'LineWidth', 0.5);
end
end
end
% 绘制匹配边
for i = 1:10
if matching(i) > 0
plot([0.5, 2.5], [i, matching(i)], 'g-', 'LineWidth', 2);
end
end
legend('左侧顶点', '右侧顶点', '可能边', '匹配边');
hold off;
算法分析与解释
匈牙利算法核心思想
匈牙利算法基于以下关键概念:
- 增广路径:从一个未匹配顶点开始,交替经过匹配边和非匹配边,最终到达另一个未匹配顶点的路径
- 核心操作:找到一条增广路径并"翻转"路径上的边(匹配变非匹配,非匹配变匹配),从而增加匹配数
MATLAB实现特点
- 深度优先搜索(DFS):使用递归DFS寻找增广路径
- 高效匹配:时间复杂度为O(mn),其中m和n分别是左右两侧顶点数
- 简洁实现:利用递归函数和访问标记数组优化搜索过程
算法步骤详解
-
初始化:
- 创建匹配数组
matching_left和matching_right,初始化为0(未匹配)
- 创建匹配数组
-
遍历左侧顶点:
- 对每个左侧顶点u,尝试寻找匹配的右侧顶点
-
DFS寻找增广路径:
- 标记已访问的右侧顶点
- 对于当前左侧顶点u连接的每个右侧顶点v:
- 如果v未访问,则标记为已访问
- 如果v未匹配,或者v已匹配但可以找到替代匹配,则更新匹配
-
更新匹配:
- 当找到增广路径时,更新匹配关系
-
结果统计:
- 计算并返回最大匹配数
参考代码 matlab实现匈牙利算法二分图最大匹配的程序 www.youwenfan.com/contentcnj/97883.html
应用场景
匈牙利算法在以下领域有广泛应用:
- 任务分配:将任务分配给最合适的工人
- 资源调度:最优资源分配问题
- 图像处理:特征点匹配
- 网络流:求解最大流问题的辅助算法
- 化学:分子结构中的键合分析
性能优化建议
对于大型二分图,可以考虑以下优化:
% 优化版本:添加早期终止和预处理
function [matching, max_match] = optimized_hungarian(adjMatrix)
[m, n] = size(adjMatrix);
matching_left = zeros(1, m);
matching_right = zeros(1, n);
% 预处理:先尝试贪心匹配
for u = 1:m
for v = 1:n
if adjMatrix(u, v) && matching_right(v) == 0 && matching_left(u) == 0
matching_left(u) = v;
matching_right(v) = u;
end
end
end
function found = dfs(u, visited)
for v = 1:n
if adjMatrix(u, v) && ~visited(v)
visited(v) = true;
% 使用匹配数组直接访问,提高效率
if matching_right(v) == 0 || dfs(matching_right(v), visited)
matching_left(u) = v;
matching_right(v) = u;
found = true;
return;
end
end
end
found = false;
end
% 只对未匹配的左侧顶点尝试DFS
for u = 1:m
if matching_left(u) == 0
visited = false(1, n);
dfs(u, visited);
end
end
max_match = sum(matching_left > 0);
matching = matching_left;
end
此优化版本添加了:
- 贪心预处理:先进行简单匹配,减少后续DFS次数
- 条件DFS:只对未匹配的左侧顶点进行DFS
- 直接访问:避免重复计算
匈牙利算法是解决二分图匹配问题的高效方法,本实现提供了清晰的MATLAB代码和示例,可直接应用于各种匹配问题。
浙公网安备 33010602011771号