匈牙利算法的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
主要特点:
-
完整的匈牙利算法实现:
- 行归约和列归约
- 独立零元素标记
- 增广路径查找
- 矩阵调整
-
处理非方阵问题:
- 自动处理代理和任务数量不等的情况
- 虚拟行/列填充
-
丰富的可视化功能:
- 成本矩阵热力图
- 关联矩阵显示
- 最优分配标记
-
实际应用示例:
- 任务分配问题
- 性能分析
- 效率评估
-
完整的测试框架:
- 多种测试用例
- 性能基准测试
- 结果验证
这个实现提供了完整的匈牙利算法解决方案,可以用于各种指派问题,并生成清晰的关联矩阵来显示最优分配结果。