最小生成树
Kruskal算法(考虑边)
Kruskal算法同样是基于贪心策略,但是它和Prim算法不同的是,在算法过程中它并不维护一个连通的分量,而是将多个连通分量合并到一起得到一颗生成树。个人觉得Kruskal算法的思想比它算法本身要重要,能够解决很多其他问题。
算法的思想:对于n个点先把图中各边的大小按照权值由小到大的顺序排列起来。最开始各个点都是独立的,先选一个权值最小的边连起来,然后选一个次小的边权值,依次类退,直到选够n-1条边即可,条件这些边不能构成圈。
算法的证明:如果一直没有构成圈,即是每条边都是按照最小,次小的顺序,这样的话,这n-1条边的权值之和肯定可以达到最小,毋庸置疑贪婪算法绝对可保证最优解,然而他可能加边的时候可能构成圈,这是按照kruskal算法,就必须把这个边去掉,换比这个边次小的边,那么就不能保证完全的贪婪。所以有必要证明。
设T是任意一个生成树(核心:选边)。
T1是由kruskal 算法得到的边
先考虑T和T1由1条边不一样:(很重要)
T1:e i1,e i2 ,e i3, e ik------e in-1;
T : ---------
e ik是第一个与T不一样的边的。
那么T肯定多了一条没在T1中的边记为e’;
既然是第一个不一样的,如果(e'大于等于e ik),自然T>T1;如果e'在(ei3到eik之间),因为T没选e',所以推理,e1,e2,e3,e'回构成圈。所以T中不可能出现这样的e',因为如果出现,又由于是第一个不一样的边,这意味着ei1,ei2,ei3都在T1中,会出现圈,所以不可能。
在依次考虑两条边不一样:
将一条边作为一个桥梁,即可得到。
缺点:在写程序时,要判断是否会构成圈,但很难写。所以出现了适合写程序的prim算法;
prim算法
Prim算法基于一种贪心的思想,通过局部最优策略,每次将一条边加入所构建的生成树中,加完n-1条边后,保证最后所得的生成树是整体最优的,即最小生成树。
算法思想:先找一个权值最小的边,然后以这两个边的端点,寻找所有与之相连的边,找权值最小,然后以这三个点为端点在找与之相连的最小的权值的边,不断加进来,直到加完n-1条边为止。
加边时,可把前面的边和点看成一个树,树的内部是不能连线(加边),可以缩成一个点,加边相当于树的生长,在外部加边。也是一种贪婪算法。
他避免了圈的形成。