【图论-匈牙利算法】Hungary Algorithm完整代码(一) 之 matlab实现

学习参考链接

博客

分配问题与匈牙利算法

带你入门多目标跟踪(三)匈牙利算法&KM算法

视频

运筹学 | 例题详解指派问题


前言

  • 图论-匈牙利算法原理参见上述参考连接中的博客与BiliBili博主的学习视屏,讲的很好很透彻。强烈建议看完(明白行列变换、找独立零、打勾、划线原理后)再来撸代码。
  • 此处以成本矩阵求解n*n的最优分配问题。

问题描述

在实际中经常会遇到这样的问题,有n项不同的任务,需要 n个人分别完成其中的一项,但由于任务的性质和各人的专长不同,因此各人去完成不同的任务的效率(或花费的时间或费用)也就不同。于是产生了一个问题,应指派哪个人去完成哪项任务,使完成 项任务的总效率最高(或所需时间最少),这类问题称为分配问题或指派问题。
在这里插入图片描述


matlab代码实现

cost矩阵(n*n)

🔺 mainHA1.m

% 定义成本矩阵
costMatrix=[2,15,13,4;10,4,14,15;9,14,16,13;7,8,11,9];
% 调用匈牙利算法计算分配的结果,已经总成本
[f,D,G]=assign(costMatrix);

匈牙利算法实现主体

🔺 assign.m

function[f,D,G]=assign(B)
% 匈牙利算法实现
% u 和 v 是包含矩阵 B 沿每一行和每一列的最小值的向量
% 从矩阵 B 的相应行和列中减去这些最小值
n=length(B(:,1));
u=min(B,[],2);
f=sum(u);%用于记录最优值
B=B-repmat(u,1,n);
v=min(B,[],1);
f=f+sum(v);%用于记录最优值
B=B-repmat(v,n,1);
C=zeros(n);
while 1
    % 在当前矩阵 B 中找到零元素,并在辅助矩阵 C 中进行标记
    C(find(B==0))=1;
    % 计算辅助矩阵 C 中每行和每列的和,存储在 u 和 v 中。
    E=C;
    u=sum(C,2);
    v=sum(C);
    % 调用 assignz 函数,该函数通过修改 C、D、G、E、u 和 v 来找到零元素的匹配。
    D=zeros(1,n);
    G=zeros(1,n);
    [C,D,G,E,u,v]=assignz(C,D,G,E,u,v);
    num=-1;
    while num<0
        add=find(D==0);
        if isempty(add)
            return;
        end
        % 调用 assignln 函数,该函数寻找未被覆盖的行,并从中找到一条增广路径
        [D,G,E,SP,TP]=assignln(D,G,E,add);
        num=numel(SP)-numel(TP);
    end
    % 更新矩阵 B,通过减去路径中的最小值,并在路径上加上最小值
    add=setdiff(1:n,TP);
    m=min(min(B(SP,add)));
    B(SP,add)=B(SP,add)-m;
    add=setdiff(1:n,SP);
    B(add,TP)=B(add,TP)+m;
    % 更新总成本 f,通过累加路径上的最小值与路径长度的乘积
    f=f+m*num;
end

标记独立零元素

assignz.m

function[C,D,G,E,u,v]=assignz(C,D,G,E,u,v)%标记独立零
while any(u)
    %  % 找到第一个u为1的行
    row=find(u==1,1);
    while row
        % 找到该行中第一个被标记为1的列
        col=find(C(row,:)==1);
        % 更新匹配关系
        D(row)=col;
        G(col)=row;
        E(row,col)=0;
        % 更新u和v
        u=u-C(:,col);
        % 清零相应的行和列
        v(col)=0;
        C(:,col)=0;
        row=find(u==1,1);
    end

    % 找到第一个v为1的列
    col=find(v==1,1);
    while col
        % 找到该列中第一个被标记为1的行
        row=find(C(:,col)==1,1);

        % 更新匹配关系
        D(row)=col;
        G(col)=row;
        E(row,col)=0;
        v=v-C(row,:);
        u(row)=0;
        C(row,:)=0;
        col=find(v==1,1);
    end
     % 如果u仍有非零元素,则找到u和v的非零元素的位置
    if any(u)
        row=find(u,1);
        col=find(C(row,:),1);
        D(row)=col;
        G(col)=row;
        E(row,col)=0;
        u=u-C(:,col);
        u(row)=0;
        v=v-C(row,:);
        v(col)=0;
        C(:,col)=0;
        C(row,:)=0;
    else return;
    end
end

划线(以最少的线覆盖所有的零)—增广路径

assignln.m

function[D,G,E,SP,TP]=assignln(D,G,E,un)%作最少的直线覆盖所有零
S=un;
SP=[];
TP=[];
F=zeros(numel(D));
while ~isempty(S)
    [null,T]=find(E(S,:));
    T=setdiff(T,TP);
    if isempty(T)
        SP=union(SP,S);
        return;
    end
    F(S,T)=E(S,T);
    SP=union(SP,S);
    TP=union(TP,T);
    Stemp=G(T);
    P=find(Stemp==0);
    if ~isempty(P)
        Tun=T(P);
        [r,c]=find(E(S,Tun),1);
        row=S(r);
        col1=Tun(c);
        while 1
            E(row,col1)=0;
            col2=D(row);
            D(row)=col1;
            G(col1)=row;
            if ismember(row,un)
                break;
            end
            E(row,col2)=1;
            row=find(F(:,col2),1);
            col1=col2;
        end
        SP=[];
        return;
    end
    S=Stemp;
end
SP=[];

运行main函数可得最短时间为28

% 输出如下
f =  28

D =  4     2     1     3

G =  3     2     4     1

f为总的时间成本,D为员工,G为任务,即员工4对应3号任务。这是最优的分配结果。


匈牙利算法实例应用

问题描述:n个点从起始位置到目标位置,如何让成本最少???

分析:以欧式距离构建成本矩阵cost

计算每个点到目标点的距离,构建权重代价

getDistance.m

function [Distance] = getDistance(Agent,Goal)
    n=length(Agent(:,1));
    m=length(Goal(:,1));
    for i=1:n
        for j=1:m
            Distance(i,j)=(Agent(i,1)-Goal(j,1))^2+(Agent(i,2)-Goal(j,2))^2;
            Distance(i,j)=sqrt(Distance(i,j));
        end
    end
end

修改mainHA1.m函数

mainHA2.m

Agent=[-5,0;0,-1;0,-2;0,-3;-1,0;-1,-1;-1,-2;-1,-3;-2,0;-2,-1;-2,-2;-2,-3;-2,-4;-2,-5];
Goal=[5,5;6,6;7,7;8,8;4,6;3,7;2,8;2,9;8,9;3,10;7,10;4,10;6,10;5,9];

matrix=getDistance(Agent,Goal);

% 执行匈牙利算法,返回分配结果
[f,D,G]=assign(matrix);

% 使用 plot 函数绘制了连接线,同时在图中用蓝色和红色分别标记位置
num=length(D);
for i=1:num
plot([Agent(i,1),Goal(D(i),1)],[Agent(i,2),Goal(D(i),2)])
hold on
plot(Agent(i,1),Agent(i,2),'.','Color','b','MarkerSize',50); 
hold on
plot(Goal(D(i),1),Goal(D(i),2),'.','Color','r','MarkerSize',50); 
hold on
end

set(gca,'XminorGrid','on');
set(gca,'YminorGrid','on');axis equal
hold off

运行main函数可得最短距离为168.3064

  • 下面是各个点的分配结果
f = 
168.3064
D =
8	11	2	4	12	14	5	1	7	10	6	13	9	3
G = 
8	3	14	4	7	11	9	1	13	10	2	5	12	6
  • 结果显示如图
    连线表示各个点的分配结果

图论-匈牙利算法matlab实现

🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑 🐑

博文中代码整理后的下载链接

  • 21
    点赞
  • 37
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SensizliKLoU

感谢您的慷慨支持和鼓励!

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值