首先是CSDN上这篇文章很清晰的讲解了匈牙利算法的思路。顺着思路本弱鸡也尝试动手写了一下。
分派问题(匈牙利算法)与MATLAB实现
匈牙利算法的matlab实现
clc;
clear;
% 主程序:基于匈牙利算法
% 输入的矩阵是前面计算好的COST(calculating_price.m)
% 需要对矩阵进行处理,基站列需要扩充,基站最多要满足M个CR用户的请求;行也需要调整。总之就是要将矩阵处理成方阵
%% 矩阵处理 - 处理成符合意义的方阵
% load('COST.mat');
COST = [1 4 3;2 inf 1;3 6 9];
[x,y] = size(COST);
COST_P = COST;
if x ~= y
% 赋值BS列
BS_column = repmat(COST(:,y),1,x-1);
COST_P = [COST_P BS_column];
% 矩阵补零变成方阵
zero = zeros(1,x+y-1);
Add_zero = repmat(zero,y-1,1);
COST_P = [COST_P;Add_zero];
end% 处理之后的COST_P矩阵应该是一个方阵
COST_expand = COST_P;
[m,n] = size(COST_P);
%% 处理矩阵 - 匈牙利算法
COST_P = rc(COST_P);
%% 计算覆盖的行数和列数
[line_sum,row_index1,row_sum1,column_index,column_sum,row_index2,row_sum2,matrix_out] = line_count(COST_P);
%% 处理划线的数量小于矩阵的维数
while (line_sum < m)
rest_min = min(min(matrix_out)); % 找到没有被覆盖的最小值,将没有被覆盖的每行减去最小值,被覆盖的每列加上最小值。转到上一步。
row_num = 1:1:m;
row_index = sort([row_index1 row_index2]);
row_num(row_index) = [];% 找到没有被覆盖的行
COST_P(row_num,:) = COST_P(row_num,:) - rest_min;% 没有被覆盖的行减去最小值
COST_P(:,column_index) = COST_P(:,column_index) + rest_min;% 被覆盖的列加上最小值
[line_sum,row_index1,row_sum1,column_index,column_sum,row_index2,row_sum2,matrix_out] = line_count(COST_P);
end
%% 输出匹配结果
[asig] = fenpei(COST_P);
if x ~= y
del_index =x+1:1:x+y-1;
asig(del_index) = []
end
%% 计算COST
cost_sum = 0;
n = length(asig);
for i = 1:n
cost_sum = cost_sum + COST_expand(i,asig(i));
end
cost_sum
行处理和列处理相对来说比较简单
function [pro_rc] = rc(matrix)
% 匈牙利算法中处理行和处理列,rc表示row和column
% 算法的第一步行减去当前行的最小值以及列减去当前列的最小值
% 输入参数是填入待处理的矩阵;输出参数是处理之后的矩阵
m = length(matrix);
for i=1:m
rowi_min = min(matrix(i,:));
matrix(i,:) = matrix(i,:)-rowi_min;
end
for i=1:m
columni_min = min(matrix(:,i));
matrix(:,i) = matrix(:,i)-columni_min;
end
pro_rc = matrix;
end
划线的处理思路是,(1)先看行,如果这个行中的0的数量大于1,则可以选择划线,line_count可以+1,并且删除掉这一行。(2)所有行中0数量大于1的处理完之后,删除掉这些行形成新的矩阵,用同样的思路处理列,在形成新的矩阵。(3)这样新的矩阵中就只剩下一种情况,每行中只有一个0(每列中只有一个0),用行算就行。
function [line_sum,row_index,row_sum,column_index,column_sum,row_index2,row_sum2,matrix_out] = line_count(matrix)
% 对处理过的矩阵进行划线统计
% 在匈牙利算法中对行和列进行划线的时候,是可以先从行开始计算,先检索有不少于两个0的行,有的话就划掉,这一个行就直接从
% 矩阵中删除掉形成新的矩阵,接着循环;列也是这样。
% 等到矩阵中都没有不少于两个0的行和列的时候,就直接以行为准,划零,统计行数;
% line_sum是划线总数,row_sum是统计行划了几条线,column_sum是统计列划了几条线,matrix_out是看最后画完线的矩阵
[m,n] = size(matrix); %统计矩阵的维度m*n
line_sum = 0;%存放划0的数量
%% 处理行
row_index = [];
j = 1;
for i=1:m
a = length(find(matrix(i,:)==0));
if a>1
line_sum = line_sum + 1;
row_index(j) = i;
j = j + 1;
end
end
row_sum = length(row_index);
matrix(row_index,:) =[]; %将输入矩阵删除掉行中含不少于2个0的行
%% 处理列
column_index = [];
k = 1;
for i=1:n
b = length(find(matrix(:,i)==0));
if b>1
line_sum = line_sum +1;
column_index(k) = i;
k = k + 1;
end
end
column_sum = length(column_index);
matrix(:,column_index) = [];
%% 处理只有一个0
[m,n] = size(matrix);%上一步处理完的矩阵有可能不是方阵
row_index2 = [];
j = 1;
for i=1:m
a = length(find(matrix(i,:)==0));
if a == 1
line_sum = line_sum +1;
row_index2(j) = i;
j = j+1;
end
end
row_sum2 = length(row_index2);
matrix(row_index2,:) = [];
matrix_out = matrix;
end
分配的思路是,行或列只有1个0的必然首先分配,并且这个0所在的行和列要不能出现0,所以直接行和列变成inf,原本想删除掉,发现有问题。最后可能会出现[0 0 ;0 0 ]这种情况,所以判断了多个0的时候直接取第一个。缺点就是没有办法显示多组解。
function [asig] = fenpei(matrix)
% 函数用于最后的分配
% 函数输入是最后的0划线数量等于矩阵的维度的最终被处理过的矩阵
% 函数的输出是最后的分配方案,[2 3 1 4]表示User1被分配到Task2,依次类推
[m,n] = size(matrix);
asig = [];% 存放决策的矩阵,[4 2 3 1]表示第一个用户被分配到任务4,以此类推
p = 1;
q = 1;
temp = length(find(matrix==0));
while (temp~=0)
%% 处理1个0
for i = 1:m
zero = length(find(matrix(i,:)==0));
if zero == 1
row_0_1(p) = i;% row_0_1表示只有1个0的行
column_row_0_1(p) = find(matrix(i,:)==0);% column_row_0_1表示只与一个0的行对应的列
asig(i) = find(matrix(i,:)==0);% 用户i被分配任务
p = p+1;
end
end
for j = 1:n
zero = length(find(matrix(:,j)==0));
if zero == 1
column_0_1(q) = j;
row_column_0_1(q) = find(matrix(:,j)==0);
asig(row_column_0_1(q)) = j;% 任务可被分配
q = q+1;
end
end
row_delete = [row_0_1 row_column_0_1];
column_delete = [column_row_0_1 column_0_1];
matrix(row_delete,:) = matrix(row_delete,:)+inf;
matrix(:,column_delete) = matrix(:,column_delete)+inf;
%% 处理多余1个0
for i = 1:m
zero = find(matrix(i,:)==0);
if length(zero) ~= 0
asig(i) = zero(1);
matrix(i,:) = matrix(i,:) + inf;
matrix(:,zero(1)) = matrix(:,zero(1)) + inf;
end
end
temp = length(find(matrix==0));
end
end
~~ 代码能力比较弱,整体代码显得比较臃肿 后面还想着继续弄一下,反正现在跑应该没啥问题了吧。~~