图论 最短路算法、最小生成树算法

本文代码无说明均为 m a t l a b matlab matlab

最短路

请添加图片描述
请添加图片描述
code:

clear;clc;
a=zeros(6);
a(1,2)=50;a(1,4)=40;a(1,5)=25;a(1,6)=10;
a(2,3)=15;a(2,4)=20;a(2,6)=25;
a(3,4)=10;a(3,5)=20;
a(4,5)=10;a(4,6)=25;
a(5,6)=55;
a=a+a';
a(find(a==0))=inf;%所有不存在的边置为正无穷
vis(1:length(a))=0;%初始化标记数组
dis(1:length(a))=inf;
dis(1)=0;
while sum(vis)<length(a)
    to=find(vis==0);%to是未访问过的节点数组
    minpos=find(dis(to)==min(dis(to)));
    %找到to中dis最小的节点在to中的位置
    now=to(minpos(1));%多个节点dis相同,取一个即可
    vis(now)=1;%标记
    dis(to)=min(dis(to),dis(now)+a(now,to));
    %这样写就可以更新to中所有节点的dis
end
dis

单源最短路—迪杰斯特拉算法

code:

function [Mindis,path]=dijkstra(a,st,ed)
% 输入:邻接矩阵a(i,j)是指i到j之间的距离,可以是有向的
% st—起点的标号, ed—终点的标号
% 输出:distance—最短路的距离, path—最短路的路径
n=size(a,1);
visited(1:n) = 0; %初始化标记数组
distance(1:n) = inf; % 保存起点到各顶点的最短距离
distance(st) = 0; 
parent(1:n) = 0;%存节点i的上一个节点 
for i = 1: n-1 
    temp=distance;
    id1=find(visited==1); %查找已经标记的点
    temp(id1)=inf; %已标号点的距离换成无穷
    [Min, now] = min(temp); %找标号值最小的顶点 
    visited(now) = 1; %标记已经标记的顶点
    id2=find(visited==0); %查找未标记的顶点
    for to = id2 %更新最短路
        if a(now, to) + distance(now) < distance(to) 
        distance(to) = distance(now) + a(now, to);
        parent(to) = now; 
        end
    end
end
path = []; 
if parent(ed) ~= 0 % ~=是不等于,这句话表示st到ed的最短路存在
    pos = ed; path = [ed];
    while pos ~= st
        p = parent(pos); 
        path = [p path];%因为是倒着找的,所以把p和之前的path拼接起来
        pos = p; 
    end 
end 
Mindis = distance(ed);

全源最短路—floyd算法

code:

function [dist,path]=floyd(a,st,ed)
% 输入:a—邻接矩阵a(i,j)是指 i 到 j 之间的距离,可以是有向的
% st—起点的标号;ed—终点的标号
% 输出:dist—最短路的距离;% path—最短路的路径
n=size(a,1); path=zeros(n); 
for i=1:n 
    for j=1:n 
        if a(i,j)~=inf 
            path(i,j)=j; %j 是 i 的后续点
        end 
    end 
end 
for k=1:n 
    for i=1:n 
        for j=1:n 
            if a(i,j)>a(i,k)+a(k,j) 
                a(i,j)=a(i,k)+a(k,j); 
                path(i,j)=path(i,k); 
            end 
        end 
    end 
end 
dist=a(st,ed); 
path=st; t=st; 
while t~=ed 
    temp=path(t,ed); 
    path=[path,temp]; 
    t=temp; 
end

最小生成树

prim算法

参数矩阵 a a a 的初始化

a=zeros(7);%首先置为方阵
a(1,2)=50; a(1,3)=60; a(2,4)=65; a(2,5)=40; 
a(3,4)=52;a(3,7)=45; a(4,5)=50; a(4,6)=30; 
a(4,7)=42; a(5,6)=70; %赋值上三角
a=a+a';%填充下三角
a(find(a==0))=inf;%不存在的边置为正无穷

code:

function result=prim(a)
%输入:邻接矩阵a(i,j)是指i到j之间的距离
%输出:result的第一、二、三行分别表示生成树边的起点、终点、权集合
%相当于一列存的是一条边
result=[];
pos=1;
n=length(a);
tb=2:n;
for i=1:n-1 %循环n-1次
    temp=a(pos,tb);
    temp=temp(:);
    d=min(temp);
    [jb,kb]=find(a(pos,tb)==d);
    j=pos(jb(1));
    k=tb(kb(1));
    result=[result,[j;k;d]];pos=[pos,k];tb(find(tb==k))=[];
end

kruskal算法

矩阵初始化,只需要赋值上三角即可

a(1,2)=50; a(1,3)=60; a(2,4)=65; a(2,5)=40; 
a(3,4)=52;a(3,7)=45; a(4,5)=50; a(4,6)=30; 
a(4,7)=42; a(5,6)=70;

code:

function result=kruskal(a)
%输入:%输入:邻接矩阵a(i,j)是指i到j之间的距离
%输出:result的第一、二、三行分别表示生成树边的起点、终点、权集合
%相当于一列存的是一条边
[i,j,b]=find(a); 
data=[i';j';b'];index=data(1:2,:); 
loop=max(size(a))-1;
result=[]; 
while length(result)<loop
    temp=min(data(3,:)); 
    flag=find(data(3,:)==temp); 
    flag=flag(1); 
    v1=index(1,flag);v2=index(2,flag); 
    if v1~=v2 
        result=[result,data(:,flag)]; 
    end 
    index(find(index==v2))=v1; 
    data(:,flag)=[]; 
    index(:,flag)=[]; 
end

旅行商问题

一名推销员准备前往若干城市推销产品,然后回到他的出发地。如何为他设计一条最短的旅行路线(从驻地出发,经过每个城市恰好一次,最后返回驻地)
请添加图片描述
一个可行的办法是首先求一个 H a m i l t o n Hamilton Hamilton C C C ,然后适当修改 C C C 以得到具有较小权的另一个 H a m i l t o n Hamilton Hamilton 圈。修改的方法叫做改良圈算法。
主函数

clear;clc;
a=zeros(6); 
a(1,2)=56;a(1,3)=35;a(1,4)=21;a(1,5)=51;a(1,6)=60; 
a(2,3)=21;a(2,4)=57;a(2,5)=78;a(2,6)=70;
a(3,4)=36;a(3,5)=68;a(3,6)=68; a(4,5)=51;a(4,6)=61; 
a(5,6)=13;
a=a+a';
a(find(a==0))=inf;
c1=[5 1:4 6]; 
[circle,long]=modifycircle(a,c1); 
c2=[5 6 1:4];%改变初始圈,起点不动
[circle2,long2]=modifycircle(a,c2); 
if long2<long 
    long=long2; 
    circle=circle2; 
end 
circle,long 
%******************************************* 
%修改圈的子函数
%******************************************* 
function [circle,long]=modifycircle(a,c1)
%输入:初始邻接矩阵a,初始圈c1,
%输出:路径轨迹circle,最小长度long
L=length(a);
flag=1; 
while flag>0
    flag=0; 
    for i=1:L-3 
        for j=i+2:L-1 
            if a(c1(i),c1(j))+a(c1(i+1),c1(j+1))<... 
                a(c1(i),c1(i+1))+a(c1(j),c1(j+1)) 
                flag=1; 
                c1(i+1:j)=c1(j:-1:i+1); 
            end
        end 
    end 
end
long=a(c1(1),c1(L)); 
for i=1:L-1 
    long=long+a(c1(i),c1(i+1)); 
end 
circle=c1;
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值