匈牙利算法的MATLAB实现

匈牙利算法的MATLAB实现,用于解决指派问题并生成关联矩阵。

1. 匈牙利算法主实现

matlab 复制代码
function [assignment, cost, association_matrix] = hungarian_algorithm(cost_matrix)
% 匈牙利算法解决指派问题
% 输入:
%   cost_matrix - 成本矩阵 (n×n),n个任务分配给n个代理的成本
% 输出:
%   assignment - 指派结果,assignment(i)表示第i个代理分配的任务编号
%   cost - 最小总成本
%   association_matrix - 关联矩阵,1表示分配,0表示未分配

[n, m] = size(cost_matrix);

% 确保成本矩阵是方阵
if n ~= m
    error('成本矩阵必须是方阵');
end

% 复制成本矩阵进行操作
C = cost_matrix;
assignment = zeros(1, n);
covered_rows = false(1, n);
covered_cols = false(1, n);
starred_zeros = zeros(n, n);  % 标记独立零元素
primed_zeros = zeros(n, n);   % 标记临时零元素

%% 步骤1: 行归约
for i = 1:n
    row_min = min(C(i, :));
    C(i, :) = C(i, :) - row_min;
end

%% 步骤2: 列归约
for j = 1:n
    col_min = min(C(:, j));
    C(:, j) = C(:, j) - col_min;
end

%% 步骤3: 寻找独立零元素
for i = 1:n
    for j = 1:n
        if C(i, j) == 0 && ~covered_rows(i) && ~covered_cols(j)
            starred_zeros(i, j) = 1;
            covered_rows(i) = true;
            covered_cols(j) = true;
        end
    end
end

covered_rows(:) = false;
covered_cols(:) = false;

%% 主循环
max_iter = 1000;
for iter = 1:max_iter
    % 步骤4: 检查是否找到完整匹配
    if sum(starred_zeros(:)) == n
        break;
    end
    
    % 找到未被覆盖的零
    [row, col] = find_uncovered_zero(C, covered_rows, covered_cols);
    
    while ~isempty(row)
        % 标记这个零
        primed_zeros(row, col) = 1;
        
        % 检查这一行是否有星标零
        star_col = find(starred_zeros(row, :), 1);
        
        if isempty(star_col)
            % 找到增广路径
            [starred_zeros, primed_zeros] = augment_path(starred_zeros, primed_zeros, row, col);
            covered_rows(:) = false;
            covered_cols(:) = false;
            primed_zeros(:) = 0;
            break;
        else
            % 覆盖这一行和这一列
            covered_rows(row) = true;
            covered_cols(star_col) = false;
            col = star_col;
            [row, col] = find_uncovered_zero(C, covered_rows, covered_cols);
        end
    end
    
    % 如果没有找到未覆盖的零,调整矩阵
    if isempty(row)
        % 找到最小未覆盖值
        min_val = find_min_uncovered(C, covered_rows, covered_cols);
        
        % 调整矩阵
        for i = 1:n
            for j = 1:n
                if covered_rows(i)
                    C(i, j) = C(i, j) + min_val;
                end
                if ~covered_cols(j)
                    C(i, j) = C(i, j) - min_val;
                end
            end
        end
        
        covered_rows(:) = false;
        covered_cols(:) = false;
        primed_zeros(:) = 0;
    end
end

%% 提取最终分配结果
for i = 1:n
    col = find(starred_zeros(i, :), 1);
    if ~isempty(col)
        assignment(i) = col;
    end
end

%% 计算总成本
cost = 0;
for i = 1:n
    if assignment(i) > 0
        cost = cost + cost_matrix(i, assignment(i));
    end
end

%% 生成关联矩阵
association_matrix = zeros(n, n);
for i = 1:n
    if assignment(i) > 0
        association_matrix(i, assignment(i)) = 1;
    end
end

fprintf('匈牙利算法完成: 最小成本 = %.2f\n', cost);
end

function [row, col] = find_uncovered_zero(C, covered_rows, covered_cols)
% 找到未被覆盖的零元素
[n, ~] = size(C);
for i = 1:n
    for j = 1:n
        if C(i, j) == 0 && ~covered_rows(i) && ~covered_cols(j)
            row = i;
            col = j;
            return;
        end
    end
end
row = [];
col = [];
end

function min_val = find_min_uncovered(C, covered_rows, covered_cols)
% 找到未被覆盖区域的最小值
[n, ~] = size(C);
min_val = inf;
for i = 1:n
    for j = 1:n
        if ~covered_rows(i) && ~covered_cols(j) && C(i, j) < min_val
            min_val = C(i, j);
        end
    end
end
end

function [starred_zeros, primed_zeros] = augment_path(starred_zeros, primed_zeros, row, col)
% 增广路径操作
path = [row, col];
current_row = row;
current_col = col;

% 查找路径
while true
    % 在当前列查找星标零
    star_row = find(starred_zeros(:, current_col), 1);
    if isempty(star_row)
        break;
    end
    path = [path; star_row, current_col];
    
    % 在当前行查找临时零
    prime_col = find(primed_zeros(star_row, :), 1);
    if isempty(prime_col)
        break;
    end
    path = [path; star_row, prime_col];
    current_col = prime_col;
end

% 沿着路径更新星标
for k = 1:size(path, 1)
    i = path(k, 1);
    j = path(k, 2);
    if starred_zeros(i, j)
        starred_zeros(i, j) = 0;
    else
        starred_zeros(i, j) = 1;
    end
end

primed_zeros(:) = 0;
end

2. 改进的匈牙利算法(处理非方阵)

matlab 复制代码
function [assignment, cost, association_matrix] = hungarian_algorithm_improved(cost_matrix)
% 改进的匈牙利算法,可以处理非方阵
% 输入:
%   cost_matrix - 成本矩阵 (n×m),n个代理分配给m个任务的成本
% 输出:
%   assignment - 指派结果
%   cost - 最小总成本
%   association_matrix - 关联矩阵

[n, m] = size(cost_matrix);

% 处理非方阵情况
if n ~= m
    max_dim = max(n, m);
    C = inf(max_dim, max_dim);
    C(1:n, 1:m) = cost_matrix;
else
    C = cost_matrix;
    max_dim = n;
end

% 调用标准匈牙利算法
[assignment_temp, cost_temp, association_matrix_temp] = hungarian_algorithm(C);

% 调整输出结果
assignment = zeros(1, n);
cost = 0;
association_matrix = zeros(n, m);

for i = 1:n
    if assignment_temp(i) <= m && assignment_temp(i) > 0
        assignment(i) = assignment_temp(i);
        cost = cost + cost_matrix(i, assignment_temp(i));
        association_matrix(i, assignment_temp(i)) = 1;
    end
end
end

3. 可视化工具函数

matlab 复制代码
function visualize_assignment(cost_matrix, assignment, association_matrix)
% 可视化指派结果
figure('Position', [100, 100, 1200, 500]);

% 子图1: 成本矩阵热力图
subplot(1, 2, 1);
imagesc(cost_matrix);
colorbar;
title('成本矩阵');
xlabel('任务编号');
ylabel('代理编号');

% 标记最优分配
[n, m] = size(cost_matrix);
hold on;
for i = 1:n
    if assignment(i) > 0 && assignment(i) <= m
        plot(assignment(i), i, 'ro', 'MarkerSize', 10, 'LineWidth', 2);
        text(assignment(i), i, sprintf('%.1f', cost_matrix(i, assignment(i))), ...
            'HorizontalAlignment', 'center', 'VerticalAlignment', 'bottom', ...
            'Color', 'white', 'FontWeight', 'bold');
    end
end
hold off;

% 子图2: 关联矩阵
subplot(1, 2, 2);
imagesc(association_matrix);
colormap([1,1,1; 0,0.5,0]); % 白色表示0,绿色表示1
title('关联矩阵');
xlabel('任务编号');
ylabel('代理编号');

% 添加数值标签
for i = 1:n
    for j = 1:m
        if association_matrix(i, j) == 1
            text(j, i, '✓', 'HorizontalAlignment', 'center', ...
                'VerticalAlignment', 'middle', 'FontSize', 14, 'Color', 'white', ...
                'FontWeight', 'bold');
        else
            text(j, i, '×', 'HorizontalAlignment', 'center', ...
                'VerticalAlignment', 'middle', 'FontSize', 10, 'Color', 'black');
        end
    end
end

% 计算并显示统计信息
total_cost = 0;
for i = 1:n
    if assignment(i) > 0 && assignment(i) <= m
        total_cost = total_cost + cost_matrix(i, assignment(i));
    end
end

fprintf('\n=== 指派结果统计 ===\n');
fprintf('总代理数: %d\n', n);
fprintf('总任务数: %d\n', m);
fprintf('已分配任务数: %d\n', sum(assignment > 0));
fprintf('最小总成本: %.2f\n', total_cost);
end

4. 测试和验证函数

matlab 复制代码
function test_hungarian_algorithm()
% 测试匈牙利算法

fprintf('=== 匈牙利算法测试 ===\n\n');

%% 测试用例1: 标准方阵问题
fprintf('测试用例1: 标准指派问题 (4×4)\n');
cost1 = [10, 19, 8, 15;
         10, 18, 7, 17;
         13, 16, 9, 14;
         12, 19, 8, 18];

[assignment1, cost1_min, assoc_matrix1] = hungarian_algorithm(cost1);
fprintf('指派结果: ');
fprintf('%d ', assignment1);
fprintf('\n最小成本: %.1f\n', cost1_min);

visualize_assignment(cost1, assignment1, assoc_matrix1);

%% 测试用例2: 非方阵问题
fprintf('\n测试用例2: 非方阵问题 (3×5)\n');
cost2 = [5, 7, 9, 6, 8;
         8, 7, 8, 6, 9;
         6, 9, 8, 7, 10];

[assignment2, cost2_min, assoc_matrix2] = hungarian_algorithm_improved(cost2);
fprintf('指派结果: ');
fprintf('%d ', assignment2);
fprintf('\n最小成本: %.1f\n', cost2_min);

figure;
visualize_assignment(cost2, assignment2, assoc_matrix2);

%% 测试用例3: 随机大规模问题
fprintf('\n测试用例3: 随机大规模问题 (8×8)\n');
rng(42); % 设置随机种子
cost3 = randi([1, 20], 8, 8);

[assignment3, cost3_min, assoc_matrix3] = hungarian_algorithm(cost3);
fprintf('指派结果: ');
fprintf('%d ', assignment3);
fprintf('\n最小成本: %.1f\n', cost3_min);

figure;
visualize_assignment(cost3, assignment3, assoc_matrix3);

%% 性能测试
fprintf('\n=== 性能测试 ===\n');
sizes = [10, 20, 50, 100];
times = zeros(size(sizes));

for i = 1:length(sizes)
    n = sizes(i);
    cost_test = randi([1, 100], n, n);
    
    tic;
    [~, ~, ~] = hungarian_algorithm(cost_test);
    times(i) = toc;
    
    fprintf('矩阵大小 %d×%d: 耗时 %.4f 秒\n', n, n, times(i));
end

% 绘制性能曲线
figure;
plot(sizes, times, 'bo-', 'LineWidth', 2, 'MarkerSize', 8);
xlabel('矩阵大小');
ylabel('计算时间 (秒)');
title('匈牙利算法性能分析');
grid on;
end

5. 应用示例:任务分配问题

matlab 复制代码
function task_assignment_example()
% 任务分配问题应用示例

fprintf('=== 任务分配问题应用示例 ===\n\n');

% 定义问题:5个工人分配5个任务
workers = {'张三', '李四', '王五', '赵六', '钱七'};
tasks = {'任务A', '任务B', '任务C', '任务D', '任务E'};

% 成本矩阵:每个工人完成每个任务的时间(小时)
cost_matrix = [8, 6, 7, 9, 5;    % 张三
               6, 7, 8, 6, 7;    % 李四
               5, 8, 7, 9, 6;    % 王五
               7, 6, 8, 7, 8;    % 赵六
               6, 7, 5, 8, 7];   % 钱七

fprintf('工人完成任务时间矩阵(小时):\n');
fprintf('工人\\任务\t');
fprintf('%s\t', tasks{:});
fprintf('\n');
for i = 1:length(workers)
    fprintf('%s\t\t', workers{i});
    for j = 1:length(tasks)
        fprintf('%d\t', cost_matrix(i, j));
    end
    fprintf('\n');
end

% 使用匈牙利算法求解
[assignment, total_time, assoc_matrix] = hungarian_algorithm(cost_matrix);

% 显示分配结果
fprintf('\n=== 最优分配方案 ===\n');
for i = 1:length(workers)
    task_idx = assignment(i);
    if task_idx > 0
        fprintf('%s 分配至 %s,耗时 %d 小时\n', ...
                workers{i}, tasks{task_idx}, cost_matrix(i, task_idx));
    end
end
fprintf('\n总耗时: %d 小时\n', total_time);

% 可视化
figure('Position', [100, 100, 1000, 600]);

% 成本矩阵可视化
subplot(1, 2, 1);
imagesc(cost_matrix);
colorbar;
title('任务完成时间矩阵 (小时)');
xlabel('任务');
ylabel('工人');
set(gca, 'XTick', 1:length(tasks), 'XTickLabel', tasks);
set(gca, 'YTick', 1:length(workers), 'YTickLabel', workers);

% 标记最优分配
hold on;
for i = 1:length(workers)
    if assignment(i) > 0
        plot(assignment(i), i, 'ro', 'MarkerSize', 12, 'LineWidth', 2);
    end
end
hold off;

% 关联矩阵可视化
subplot(1, 2, 2);
imagesc(assoc_matrix);
colormap([1,1,1; 0,0.7,0]);
title('最优分配关联矩阵');
xlabel('任务');
ylabel('工人');
set(gca, 'XTick', 1:length(tasks), 'XTickLabel', tasks);
set(gca, 'YTick', 1:length(workers), 'YTickLabel', workers);

% 添加分配标记
for i = 1:length(workers)
    for j = 1:length(tasks)
        if assoc_matrix(i, j) == 1
            text(j, i, '✓', 'HorizontalAlignment', 'center', ...
                'VerticalAlignment', 'middle', 'FontSize', 16, 'Color', 'white', ...
                'FontWeight', 'bold');
        end
    end
end

% 效率分析
fprintf('\n=== 效率分析 ===\n');
avg_time_per_worker = total_time / length(workers);
fprintf('平均每个工人耗时: %.2f 小时\n', avg_time_per_worker);

% 计算负载均衡度
individual_times = zeros(1, length(workers));
for i = 1:length(workers)
    if assignment(i) > 0
        individual_times(i) = cost_matrix(i, assignment(i));
    end
end
load_balance_std = std(individual_times);
fprintf('负载均衡度(标准差): %.2f 小时\n', load_balance_std);
end

6. 使用示例

matlab 复制代码
% 主程序示例
clear; clc; close all;

% 运行测试
test_hungarian_algorithm();

% 运行应用示例
task_assignment_example();

% 单独使用示例
fprintf('\n=== 单独使用示例 ===\n');
% 创建一个成本矩阵
cost_matrix = [15, 20, 18, 22;
               19, 16, 21, 17;
               23, 19, 16, 20;
               18, 22, 19, 15];

[assignment, cost, association_matrix] = hungarian_algorithm(cost_matrix);

fprintf('成本矩阵:\n');
disp(cost_matrix);
fprintf('最优指派: ');
disp(assignment);
fprintf('最小成本: %.1f\n', cost);
fprintf('关联矩阵:\n');
disp(association_matrix);

参考代码 实现匈牙利算法,最终产生关联矩阵 www.youwenfan.com/contentcsm/65028.html

主要特点:

  1. 完整的匈牙利算法实现

    • 行归约和列归约
    • 独立零元素标记
    • 增广路径查找
    • 矩阵调整
  2. 处理非方阵问题

    • 自动处理代理和任务数量不等的情况
    • 虚拟行/列填充
  3. 丰富的可视化功能

    • 成本矩阵热力图
    • 关联矩阵显示
    • 最优分配标记
  4. 实际应用示例

    • 任务分配问题
    • 性能分析
    • 效率评估
  5. 完整的测试框架

    • 多种测试用例
    • 性能基准测试
    • 结果验证

这个实现提供了完整的匈牙利算法解决方案,可以用于各种指派问题,并生成清晰的关联矩阵来显示最优分配结果。

相关推荐
毕设源码-钟学长41 分钟前
【开题答辩全过程】以 基于springboot农科所农作物信息管理系统的设计与实现为例,包含答辩的问题和答案
java·spring boot·后端
路过君_P44 分钟前
C++ 算法题解:迷宫寻路
c++·算法·深度优先
罗湖老棍子1 小时前
二维vector完全指南1:从定义到增删改查
数据结构·c++·算法·stl
再卷也是菜1 小时前
C++篇(22)LRU Cache
数据结构·c++·算法
语落心生1 小时前
海量数据集的AI自动化预测打标 -- 振动特征多标签分类
算法
语落心生1 小时前
海量数据集AI自动化打标 - 温度周期检测
算法
语落心生1 小时前
海量数据集的AI自动化预测打标 -- 矿业音频分类
算法
吃着火锅x唱着歌1 小时前
LeetCode 3185.构成整天的下标对数目II
算法·leetcode·职场和发展
鱼鱼块1 小时前
《最小栈的巧妙设计:用辅助栈实现 O(1) 获取最小值》
javascript·算法·面试