方法一:克鲁斯卡尔(Kruskal)算法
用来求加权连通图的最小生成树的算法
算法思想:
1、对图的所有边按照权值大小进行排序
2、依次将最小边添加到最小生成树中,需要判断这条边是否构成了回路,如果构成回路则不能加入
针对这两个问题的具体实现细节
1、对图的所有边按照权值大小进行排序即可
2、记录每个顶点在最小生成树中的终点,每次要添加一条边时,判断该边的两个顶点的终点是否重合,如果重合说明存在回路
所需变量:
1、二维数组matrix:保存顶点与顶点之间的边长度
2、一维数组int[] end:保存各个顶点的终点
3、链表result:保存最终的最小生成树
4、还需要把二维数组matrix的边保存到一个类中,做排序,该类可以设置属性变量有两个顶点和边长度
代码
public int minCostConnectPoints(int[][] points) {
int n = points.length;
List<int[]> edge = new ArrayList<>();
for(int i=0;i<n;++i)
{
for(int j=i+1;j<n;++j)
{
if(points[i][j]!=0)
edge.add(new int[]{i,j,distance(points[i],points[j])});
}
}
// edge.sort(new Comparator<int[]>() {
// @Override
// public int compare(int[] o1, int[] o2) {
// return o1[2]-o2[2];
// }
// });
//排序
edge.sort((a,b)->a[2]-b[2]);
//计算是否有回路
union uf = new union(n);
int ans = 0;
int num =1;
//从大到小遍历边
for(int[] tmp:edge)
{
if(uf.union(tmp[0],tmp[1]))
{
ans = ans + tmp[2];
//如果边总数n了就跳出,为什么这里是++num
}
}
return ans;
}
public class union
{
int[] father;
public union(int n)
{
//初始化
this.father = new int[n];
for(int i=0;i<n;++i)
father[i] = i;
}
//找终点
public int find(int x)
{
while(father[x]!=x)
{
x = father[x];
}
return x;
}
public boolean union(int x,int y)
{
int fx = find(x);
int fy = find(y);
if(fx!=fy) {
//更新终点
father[fx] = fy;
return true;
}
return false;
}
}
public int distance(int[] a,int[] b)
{
return Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
}
方法二、prime方法
prime算法和求最短路径的思想很像,是一种贪心算法
1、将图中任意顶点加入最小生成树
2、将该顶点所有的边加入一个边集合
3、从该边集合找到最小边,并把该边的另一顶点加入最小生成树
4、重复步骤二
5、直至所有顶点都加入最小生成树
所需变量:
int[] visited:以为数组,用来判断顶点是否加入最小生成树了
相当于邻接表,数组链表List<int[]>[] graph:保存每个顶点的边和距离
queue<int[]>:小根堆,用来维护边集合,每次弹出来的都是最小边
代码:
//普利姆算法
public class minTree {
boolean[] visited;
PriorityQueue<int[]> queue ;
List<int[]>[] graph;
public int minCostConnectPoints(int[][] points)
{
graph = buildGraph(points);
visited = new boolean[points.length];
queue = new PriorityQueue<>((o1, o2) -> o1[2]-o2[2]);
visited[0] = true;
cut(0);
int minlen = 0;
while(!queue.isEmpty())
{
int[] node = queue.poll();
if(visited[node[1]])
continue;
minlen = minlen+node[2];
visited[node[1]] = true;
cut(node[1]);
}
return minlen;
}
public void cut(int start)
{
for(int[] tmp:graph[start])
{
int j = tmp[1];
if(visited[j])
continue;
queue.offer(new int[]{start,j,tmp[2]});
}
}
public List<int[]>[] buildGraph(int[][] points)
{
List<int[]>[] graph = new LinkedList[points.length];
for(int i =0;i<points.length;++i)
{
graph[i] = new LinkedList<>();
}
for(int i=0;i<points.length;++i)
{
for(int j=i+1;j<points.length;++j)
{
graph[i].add(new int[]{i,j,distance(points[i],points[j])});
graph[j].add(new int[]{j,i,distance(points[i],points[j])});
}
}
return graph;
}
public int distance(int[] a, int[] b)
{
return Math.abs(a[0]-b[0])+Math.abs(a[1]-b[1]);
}
}