1. 程式人生 > 其它 >圖論(2)--最短路徑和最小生成樹

圖論(2)--最短路徑和最小生成樹

圖的最短路徑問題

問題描述

Matlab求解最短路徑

s = [9 9 1 1 2 2 2 7 7 6 6  5  5 4];
t = [1 7 7 2 8 3 5 8 6 8 5  3  4 3];
w = [4 8 3 8 2 7 4 1 6 6 2 14 10 9];
G = graph(s,t,w);
plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2) 
set( gca, 'XTick', [], 'YTick', [] );  
[P,d] = shortestpath(G, 9, 4)  %注意:該函式matlab2015b之後才有哦 P裡面儲存的就是最短路徑上面的節點

% 在圖中高亮我們的最短路徑
myplot = plot(G, 'EdgeLabel', G.Edges.Weight, 'linewidth', 2);  %首先將圖賦給一個變數
highlight(myplot, P, 'EdgeColor', 'r')   %對這個變數即我們剛剛繪製的圖形進行高亮處理(給邊加上r紅色)

% 求出任意兩點的最短路徑矩陣
D = distances(G)   %注意:該函式matlab2015b之後才有哦
D(1,2)  % 1 -> 2的最短路徑
D(9,4)  % 9 -> 4的最短路徑

% 找出給定範圍內的所有點  nearest(G,s,d)
% 返回圖形 G 中與節點 s 的距離在 d 之內的所有節點
[nodeIDs,dist] = nearest(G, 2, 10)   %注意:該函式matlab2016a之後才有哦

求最短路徑演算法

求解最短路徑演算法主要包括迪傑斯特拉演算法和弗洛伊德演算法

強烈推薦觀看視訊:圖論最短距離(Shortest Path)演算法動畫演示-Dijkstra(迪傑斯特拉)和Floyd(弗洛伊德)_嗶哩嗶哩_bilibili

迪傑斯特拉演算法的matlab實現

function [mydistance,mypath]=mydijkstra(a,sb,db);
%輸入:a——鄰接矩陣;a(i,j)——i到j之間的距離,可以是有向的
%sb——起點的標號,db——終點的標號
%輸出:mydistance——最短路的距離,mypath——最短路的路徑

n=size(a,1);visited(1:0)=0;
distance(1:n)=inf;distance(sb)=0;	%起點到各頂點距離的初始化
visited(sb)=1;u=sb;		%u為最新的S集合頂點
parent(1:0)=0;		%前驅頂點的初始化
for i=1:n-1
	id=find(visited==0);	%查詢V-S集合的頂點
	for v=id
		if a(u,v)+distance(u)<distance(v)
			distance(v)=distance(u)+a(u,v);		%修改標號值
			parent(v)=u;
		end
	end
	temp=distance;
	temp(visited==1)=inf;	%已標號點的距離換成無窮大
	[t,u]=min(temp);	%找標號值最小的頂點
	visited(u)=1;	%標記已經標號的頂點
end
mypath=[];
if parent(db)~=0 	%如果存在路!
	t=db;mypath=[db];
	while t~=sb
		P=parent(t);
		mypath=[P mypath];
		t=P;
	end
end
mydistance=distance(db);

弗洛伊德演算法的matlab實現

function [dist,path]=myfloyd(a)
%尋找i,j兩點最短路徑
% 輸入:a—鄰接矩陣,元素(aij)是頂點i到j之間的直達距離,可以是有向的
% sb—起點的標號;db—終點的標號
% 輸出:dist—最短路的距離;% path—最短路的路徑
n=size(a,1);
m=a;
for i=1:n   %path矩陣的初始化
    for j=1:n
        path(i,j)=j;
    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)=k;
            end
        end
    end
end
for sb=1:n
   for db=1:n
      t=path(sb,db);
      dist(sb,db)=m(sb,t);
       while t~=db
         p=path(t,db);        
         dist(sb,db)=dist(sb,db)+m(t,db);
         t=p;
       end
    end
end

最小生成樹

連通賦權圖的具有最小權的生成樹叫做最小生成樹

問題描述

求解最小生成樹的演算法有Kruskal(克魯斯卡爾)和Prim(普里姆)演算法:

觀看視訊:最小生成樹(Kruskal(克魯斯卡爾)和Prim(普里姆))演算法動畫演示_嗶哩嗶哩_bilibili

Kruskal演算法matlab實現

%邊權矩陣,每一列都表示一條邊,從上到下分別為兩個頂點以及它們邊的權值
b = [1 1 1 2 2 3 3 4;
     2 4 5 3 5 4 5 5;
     8 1 5 6 7 9 10 3];
%sortrows函式對某一列進行比較排序,所以我們先轉置b矩陣,然後對第三列也就是權值進行排序
[B,i]=sortrows(b',3);
%再將其轉置回來
B=B';
%m為邊的條數,n為點的個數
m=size(b,2);n=5;
%t陣列用來標記選中的邊,k用來計數,T矩陣用來儲存選中的邊,c計算最小生成樹的總長度
t=1:n;k=0;T=[];c=0;

for i=1:m
    if t(B(1,i))~=t(B(2,i))
        k=k+1;T(k,1:2)=B(1:2,i),c=c+B(3,i);
        tmin=min(t(B(1,i)),t(B(2,i)));
        tmax=max(t(B(1,i)),t(B(2,i)));
        for j=1:n
            if t(j)==tmax
                t(j)=tmin;
            end
        end
    end
    if k==n-1
        break;
    end
end
T,c,

來源:【MATLAB】最小生成樹Kruskal演算法_taoxing-CSDN部落格_kruskal演算法

Prim演算法matlab實現

function [result]=myprim(a)//a為傳入的每個點的距離矩陣
result=[];//用result(3×n)矩陣來表示,第一行表示起點,第二行表示終點,第三行表示權值
p=1;tb=2:length(a);
while size(result,2)~=length(a)-1
    temp=a(p,tb);temp=temp(:);
    d=min(temp);
    [jb,kb]=find(a(p,tb) == d,1);
    j=p(jb);k=tb(kb);
    result=[result,[j;k;d]];p=[p,k];tb(find(tb==k))=[];
end

result第一行表示起點,第二行表示終點,第三行表示權值

來源:數模:最小生成樹prim演算法(通用matlab程式碼)_萌新的部落格-CSDN部落格_prim演算法matlab程式碼