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;

算法分析与解释

匈牙利算法核心思想

匈牙利算法基于以下关键概念:

  1. 增广路径:从一个未匹配顶点开始,交替经过匹配边和非匹配边,最终到达另一个未匹配顶点的路径
  2. 核心操作:找到一条增广路径并"翻转"路径上的边(匹配变非匹配,非匹配变匹配),从而增加匹配数

MATLAB实现特点

  1. 深度优先搜索(DFS):使用递归DFS寻找增广路径
  2. 高效匹配:时间复杂度为O(mn),其中m和n分别是左右两侧顶点数
  3. 简洁实现:利用递归函数和访问标记数组优化搜索过程

算法步骤详解

  1. 初始化

    • 创建匹配数组matching_leftmatching_right,初始化为0(未匹配)
  2. 遍历左侧顶点

    • 对每个左侧顶点u,尝试寻找匹配的右侧顶点
  3. DFS寻找增广路径

    • 标记已访问的右侧顶点
    • 对于当前左侧顶点u连接的每个右侧顶点v:
      • 如果v未访问,则标记为已访问
      • 如果v未匹配,或者v已匹配但可以找到替代匹配,则更新匹配
  4. 更新匹配

    • 当找到增广路径时,更新匹配关系
  5. 结果统计

    • 计算并返回最大匹配数

参考代码 matlab实现匈牙利算法二分图最大匹配的程序 www.youwenfan.com/contentcnj/97883.html

应用场景

匈牙利算法在以下领域有广泛应用:

  1. 任务分配:将任务分配给最合适的工人
  2. 资源调度:最优资源分配问题
  3. 图像处理:特征点匹配
  4. 网络流:求解最大流问题的辅助算法
  5. 化学:分子结构中的键合分析

性能优化建议

对于大型二分图,可以考虑以下优化:

% 优化版本:添加早期终止和预处理
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

此优化版本添加了:

  1. 贪心预处理:先进行简单匹配,减少后续DFS次数
  2. 条件DFS:只对未匹配的左侧顶点进行DFS
  3. 直接访问:避免重复计算

匈牙利算法是解决二分图匹配问题的高效方法,本实现提供了清晰的MATLAB代码和示例,可直接应用于各种匹配问题。

posted @ 2025-10-21 11:02  别说我的眼泪有点咸  阅读(31)  评论(0)    收藏  举报