这几天玩得比较多,就写了几道最小生成树的题,都是模板题就不贴了,写下最小生成树和次最小生成树的原理,加深加深印象吧。
最小生成树
网络上也有很多博客讲这个,我就按我自己的想法讲。
1.普里姆算法。
这个算法有贪心的思想。每次都选取最短的一条边,之后更新dist[]数组和visited[]数组。
数组代表的含义:map[][]记录各个点之间的距离,dist[]记录此时到各个点的最短距离,visited[]记录已走过的点。
算法实现:初始化-任取一个点作为起点,(eg:选第1个点作为起点),则visited[1]=1,for(I<-1 ~ n) dist[I]=map[1][I];之后每次都选取dist[]数组中的最小值,代表着我从这走到了我选的这个点上,所以权值加上这个距离,再将visited[]标记为1,之后因为我们走过的点中新加入了一个点,所以我们可选的边也多了,所以我们要更新dist[]数组,if(dist[I]>map[re][I]) 则更新....这的意思是我从re这个点走到I点比你之前所选的路(走到I点的路)更短,所以我们让dist[I]=map[re][I],这的re即是我们新加入的点。这些操作要循环n-1次(n是点的个数)。
另:求最短路也可这样操作。
2.克鲁斯卡尔算法。
这个算法需要知道些并查集的知识。我贴一个博客,讲得很好:并查集。
这个算法是一开始将n个点都看成是只有自己的n个集合,之后从小到大选边,一条边选好后就将其合并成一个集合。所以就可以通过这个来判断是否可以选这条边,就是加入边前,先查看这条边的起点和终点是否再同一个集合中,如果在的话就不能选,选了的话必然有环。这个算法操作简单,理解判断是否可以加边那里(并查集)就可以了。
次最小生成树
求次最小生成树的想法:在最小生成树中加入一条之前没用过的边,这样就会形成环,之后再去掉环中权值最大的一条边,循环这个操作,直到将之前没用过的边都用上,在这过程中的最小值就是次最小生成树。
最小生成树有两种,次最小生成树自然也有两种。
1.用普里姆算法求最小生成树,不过在这过程中,我们新加入一个数组path[][],pre[],pre[]数组的含义是从哪
走到第I个点的,他与dist[]数组对应。比如说:我某一次操作,走到了第m点,对dist[]数组进行更新时,如果dist[I]>pre[m][I] 则pre[I]=m。path[][]数组的含义是三个点所构成的环中权值最大的一条边的权值。比如,path[m][n]代表的就是第m个点,第n个点和第pre[m]个点所构成环的边中最大的一条。
2.用克鲁斯卡尔算法求最小生成树,在这过程中,我们将用过的边标记起来。之后再以相同的方法求次最小生成树。循环n-1次,每一次都选一条在最小生成树的边将其搁置。意思就是我们在最小生成树中去掉一条边,然后加上另外一条边,求其中的最小值。