最小生成树(MST)

转自:https://www.cnblogs.com/fanmu/p/6082152.html

最小生成树

1.定义

2.kruskal 算法

3.Prim 算法

 

1.定义

G=(V,E)为连通无向图,V为结点的集合,E为结点的可能连接边

对每条边(u ,v)都赋予权重w(u ,v)

目标:找到一个无环子集T, 既能将所有结点连接起来,又具有最小权重。

T是由G生成的树,并把这种问题叫做最小生成树问题。

 

2.kruskal算法

主要思想:

将V的每个结点定义为一棵树,并定义根节点(代表)为该节点,将E中的边按权重从小到大依次处理。

首先判断边的两个结点是否属于同一棵树(根据根节点是否一致),若不是,则合并两棵树,并更新根节点;若是,则不予理会。

(这里是为了形成无环集合,保证权重和最小

如下图f所示,结点i、g已合并为一棵树,根节点一致,所以ig边不再纳入集合)

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
global G
G.VV= char (97:105);
G.V= cell (9,1);
G.Adj={ 'ab' ; 'ah' ; 'bc' ; 'bh' ; 'hi' ; 'hg' ; 'ig' ; 'gf' ; 'cf' ; 'cd' ; 'df' ; 'de' ; 'ef' ; 'ic' };
G.Bdj=[4;8;8;11;7;1;6;2;4;7;14;9;10;2];
A=[];
for i =1: length (G.VV) %MAKE-SET
     G.V{ i }.p=G.VV( i );
     G.V{ i }. rank =0;
end
[wei,index]= sort (G.Bdj);
la=G.Adj(index);
for i =1: length (la)
     x=la{ i };
     a1= find (G.VV==x(1));
     a2= find (G.VV==x(2));
     if find_set(a1)~=find_set(a2)
         A=[A;x];
         union (a1,a2);
     end
end
 
 
function  k= find_set( i )
%找到集合的代表,也就是根节点
global G
if G.V{ i }.p~=G.VV( i ) %这里的G.V{i}.p是G.VV(i)所在子树的根节点
     %函数的目标是找到合并之后的树(集合)的的结点
     j = find (G.VV==G.V{ i }.p);
     G.V{ i }.p=find_set( j ); %不断更新,直到找到集合的根节点
end
k=G.V{ i }.p;
end
 
function union ( i ,a)
%合并两个集合,并更新集合的根节点
%更新的原则是看子树的结点数目,多的那个的子树的代表当根节点
%注意,这里并没有更新子树的根节点,这一步骤是在find_set里完成的
global G
x=find_set( i );
y=find_set(a);
aa= find (G.VV==x);
bb= find (G.VV==y);
if G.V{aa}. rank >G.V{bb}. rank
     G.V{bb}.p=G.VV(aa);
else
     G.V{aa}.p=G.VV(bb);
     if G.V{aa}. rank ==G.V{bb}. rank
         G.V{bb}. rank =G.V{bb}. rank +1;
     end
end 
end

  

运行结果:

A =

hg
gf
ic
ab
cf
cd
ah
de

d=37

 

3.prim 算法

关于轻量级边的定义:

 

主要思想:

给定连通图G和任意根节点r,最小生成树从结点r开始,一直长大到覆盖V中所有结点为止,即不断寻找轻量级边以实现最小权重和

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
%最小生成树-prim算法
G.VV= char (97:105);
G.Adj={ 'bh' ; 'ahc' ; 'bifd' ; 'cfe' ; 'df' ; 'cdeg' ; 'ihf' ; 'abig' ; 'cgh' }; %邻接链表
G.Bdj={[4 8];[4 11 8];[8 2 4 7];[7 14 9];[9 10];[4 14 10 2];[6 1 2];[8 11 7 1];[2 6 7]}; %邻接链表对应权重
Q=G.VV;
Q(Q==G.VV(1))=[];
r=1;
x(r)=G.VV(1); %给定初始点
d=0;
 
while length (Q)~=0
     [wei,index]= sort (unionwei(G,x,r)); %!!!关键点,目的是横跨(V-Q,Q)的轻量级边的一个端点,即权重最小的一个点
     u=unionla(G,x,r);
     u=u(index);
     for i =1: length (u)
         if find (Q==u( i ))
             k= i ;
             break ;
         end
     end
     d=d+wei(k);
     r=r+1;
     x(r)=u(k);
         
     Q(Q==u(k))=[]; %找到后Q中删除,以保证每个点只被访问一次
end
fprintf ( 'path:' );x
fprint( '\n' );
fprintf ( 'd= %d \n' ,d);
 
 
function wei0=unionwei( G,x,r )
%合并权重向量,方便排序
wei0=[];
for i =1:r
     a= find (G.VV==x( i ));
     wei1=G.Bdj{a};
     wei0=[wei0 wei1];
end
end
 
function la0 = unionla(G,x, r )
%合并权重对应的边
la0=[];
for i =1:r
     a= find (G.VV==x( i ));
     la1=G.Adj{a};
     la0=[la0 la1];
end
end

  

  

运行结果:

path:
x =

abhgfcide


d= 37

转载于:https://www.cnblogs.com/leebxo/p/10179558.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值