上图是一个带有回路的简单带权图。即两点间可能不只有一种到达方式,且每条边都带有权值。
在实际生产环境中,可将此图看作是城市间线缆的建造成本,或者拼车时送达各乘客的路线成本。
而避圈法是为了在这种图的基础上,得到一条连接所有点,且总权值最小的图。
在《图论》中称作该图权重最小的最小生成树,如下图:
测试类:
package mintree;
import java.util.List;
/**
* @author sean22
* @date 2018/1/30/030.
*/
public class Test {
public static void main(String[] args) {
int X = Kruskal.X;
int[][] matrix = {
{X,X,X,3,4,X},
{X,X,2,X,5,X},
{X,2,X,X,X,4},
{3,X,X,X,X,2},
{4,5,X,X,X,3},
{X,X,4,2,3,X}
};
List lines = Kruskal.getASCLines(matrix);
Kruskal.loadPath(lines,matrix);
Kruskal.print(matrix);
}
}
package mintree;
import java.util.Collections;
import java.util.LinkedList;
import java.util.List;
/**
* @author sean22
* @date 2017/12/13/013.
* 避圈法
*/
public class Kruskal {
static int X = Integer.MAX_VALUE;
public static List getASCLines(int[][] matrix){
List lines = new LinkedList<>();
for(int i=0;i lines,int[][] matrix){
Path r = new Path();
List exist = new LinkedList<>();
for(int i=0;i
package mintree;
import java.util.LinkedList;
import java.util.List;
/**
* @author sean22
* @date 2017/12/14/014.
*/
public class Path {
List> nodes;
Path(){
nodes = new LinkedList<>();
}
/**
* @param line
* @return true 添加成功,false 形成回路,添加失败
*/
public boolean add(Line line){
int added =Integer.MAX_VALUE;
for(int n=0;n node = nodes.get(n);
boolean startEqual =false;
boolean endEqual = false;
for(int i=0;i list = new LinkedList<>();
list.add(line.startPos);
list.add(line.endPos);
nodes.add(list);
}
return true;
}
/**
* line若是桥,合并两个node
*/
public void bindNodesIfBridge(List>nodes,int added,List node){
if(added!=Integer.MAX_VALUE){
nodes.get(added).addAll(node);
nodes.remove(node);
}
}
}
线段对象:
package mintree;
/**
* Created by sean on 2017/12/13/013.
*/
public class Line implements Comparable{
int startPos;
int endPos;
int quality;
Line(int startPos,int endPos,int quality){
this.startPos = startPos;
this.endPos = endPos;
this.quality = quality;
}
@Override
public String toString() {
return "("+startPos+"<->"+endPos+"="+quality+")";
}
@Override
public int compareTo(Line o) {
return this.quality-o.quality;
}
}
1. 首先初始化邻接矩阵(矩阵中记录了点到点间的连接关系,其中X表示两点不可达。),将其转换为一个Line
对象的集合(舍弃不可达的路径)。
2.然后将线段在集合中按升序排列。【按升序排列可以保证在添加一条线段形成回路时,这条线段在回路中总是权值最高的。
那么删掉该线段即可】。
3.依次读取线段,将出现以下四种情况:
(1)Path的nodes中的所有数组均不包含当前线段的任意端点。
执行:在nodes中新建一个数组,保存线段的两个端点。【即新建一条通路】
(2)当前线段的一个端点已在nodes的某一个数组中,但另一个端点未在nodes中所有数组找到。
执行:将未保存的另一个端点保存在存在端点的数组中。【在当前通路中添加一条线段】
(3)当前线段的一个端点在nodes的某一个数组,另一个端点在nodes中的另一个数组。
执行:合并两个数组。【当前线段作为桥连接起了两条通路】
(4) 当前线段的两个端点都已经存在在同一个数组中。
执行:舍弃当前线段。【形成了回路】
最终,若此图是一个连通图,一定可以将所有的通路通过(2)连接到一起,并避开所有回路,得到最小权值和的连通图。