????????最小生成树(MST)问题是网络设计中常见的问题。想象一下,你的公司有几间办公室,要
以最低的成本实现办公室电话线路相互连通,以节省资金,最好的办法是什么?
????????这也可以应用于岛桥问题。设想你要在n个岛屿之间建造桥梁,想用最低的成本实现所有岛
屿相互连通。
????????这两个问题都可以用MST算法来解决,其中的办公室或者岛屿可以表示为图中的一个顶点,
边代表成本。这里我们有一个图的例子,其中较粗的边是一个MST的解决方案。
????????Prim算法是一种求解加权无向连通图的MST问题的贪心算法。它能找出一个边的子集,使得
其构成的树包含图中所有顶点,且边的权值之和最小。
????????现在,通过下面的代码来看看Prim算法是如何工作的:
this.prim = function() {
var parent = [],
key = [],
visited = []
length = this.graph.length,
i
for (i = 0; i < length; i++) { //{1}
key[i] = INF
visited[i] = false
}
key[0] = 0 //{2}
parent[0] = -1
for (i = 0; i < length-1; i++) { //{3}
var u = minKey(key, visited) //{4}
visited[u] = true //{5}
for (var v = 0; v < length; v++) {
if (this.graph[u][v] && visited[v] == false && this.graph[u][v] < key[v]) { //{6}
parent[v] = u //{7}
key[v] = this.graph[u][v] //{8}
}
}
}
return parent //{9}
}
下面是对算法过程的描述。
? 行{1}:首先,把所有顶点(key)初始化为无限大(JavaScript最大的数INF = Number.MAX_
SAFE_INTEGER),visited[]初始化为false。
? 行{2}:其次,选择第一个key作为第一个顶点,同时,因为第一个顶点总是MST的根节点,所以parent[0] = -1。
? 行{3}:然后,对所有顶点求MST。
? 行{4}:从未处理的顶点集合中选出key值最小的顶点(与Dijkstra算法中使用的函数一样,只是名字不同)。
? 行{5}:把选出的顶点标为visited,以免重复计算。
? 行{6}:如果得到更小的权值,则保存MST路径(parent,行{7})并更新其权值(行{8})。
? 行{9}:处理完所有顶点后,返回包含MST的结果。
????????和Prim算法类似,Kruskal算法也是一种求加权无向连通图的MST的贪心算法。
????????现在,通过下面的代码来看看Kruskal算法是如何工作的:
this.kruskal = function() {
var length = this.graph.length,
parent = [], cost,
ne = 0, a, b, u, v, i, j, min
cost = initializeCost() //{1}
while (ne < length-1) { //{2}
for (i = 0, min = INF; i < length; i++) { //{3}
for (j = 0; j < length; j++) {
if (cost[i][j] < min) {
min = cost[i][j]
u = i
v = j
}
}
}
u = find(u, parent) //{4}
v = find(v, parent) //{5}
if (union(u, v, parent)) { //{6}
ne++
}
cost[u][v] = cost[v][u] = INF //{7}
}
return parent
}
var find = function(i, parent) {
while (parent[i]) {
i = parent[i]
}
return i
}
var union = function(i, j, parent) {
if (i != j) {
parent[j] = i
return true
}
return false
}
下面是对算法过程的描述。
? 行{1}:首先,把邻接矩阵的值复制到cost数组,以方便修改且可以保留原始值行{7}。
? 行{2}:当MST的边数小于顶点总数减1时。
? 行{3}:找出权值最小的边。
? 行{4}和行{5}:检查MST中是否已存在这条边,以避免环路。
? 行{6}:如果u和v是不同的边,则将其加入MST。
? 行{7}:从列表中移除这些边,以免重复计算。
? 行{8}:返回MST。