一个连通图的最小连通子图(再去掉一条边就不是连通的),一般针对于带权图,即在原图当中边的权值最小的一棵生成树
特性
- 一个连通图可以有很多棵生成树
- 不存在环
Kruskal算法(贪心)
从局部最优到整体最优,不断选择当前最优的。从边出发
- 先把所有的边按降序排列
- 从小到大添加,遇到环跳过(采用并查集判断)
浅谈贪心算法与动态规划
贪心算法是自顶向下,当我们想要要求解的问题可以通过局部最优的选择来达到,不断迭代,最优子结构。贪心不能保证最后的解一定是最佳的,只能求解一下满足某一些约定条件的可行解
动态规划是自底向上,也是不断拆解子问题但是目标明确
public class Kruskal {
public void kruskal(MyGraph myGraph){
int edgCount = 0;
//使用简单的冒泡排序对边集数组按距离从小到大排序
for (int i = 0; i < myGraph.eNums - 1; i++) {
for (int j = 0; j < myGraph.eNums - i - 1; j++) {
if(myGraph.edges[j].weight>myGraph.edges[j+1].weight){
int temp = myGraph.edges[j].weight;
myGraph.edges[j].weight = myGraph.edges[j+1].weight;
myGraph.edges[j+1].weight = temp;
}
}
}
//初始化
int[] parent = new int[myGraph.vNums];
for (int i = 0; i < myGraph.vNums; i++) {
parent[i] = i;
}
for (int i = 0; i < myGraph.eNums; i++) {
int begin = find(parent,parent[myGraph.edges[i].begin]);
int end = find(parent,parent[myGraph.edges[i].end]);
if(begin != end){
//如果两个结点的根结点不一样说明不会形成环路
parent[begin] = end;
edgCount++;
if(edgCount == myGraph.eNums - 1){
break;
}
}
}
}
/**
* 并查集思想查找根结点
* @param parent 父结点数组
* @param index 查找的结点下标
* @return 根结点
*/
public int find(int[] parent,int index){
//直到找到根结点
while(parent[index]!=index){
index = parent[index];
}
return index;
}
}
Prim算法
普⾥姆算法在找最⼩⽣成树时,将顶点分为两类,⼀类是在查找的过程中已经包含在⽣成树
中的顶点,剩下的为不在集合里的。
- 选初始结点,将它移到集合里
- 找出与集合里顶点相连接的权值最小的顶点,将其加入集合
- 重复步骤2
public class Prim {
public void prim(MGraph mGraph){
//保存相关顶点的下标
int[] adjvex = new int[mGraph.vNums];
//保存当前集合到各个顶点的最小权值
int[] lowcost = new int[mGraph.vNums];
//将v0加入集合
lowcost[0] = 0;
for (int i =1;i< mGraph.vNums;i++){
adjvex[i] = 0;//初始化
lowcost[i] = mGraph.arcs[0][i];//初始集合到各个顶点的最小权值即v0到各个顶点的权值
}
//构造最小生成树
for (int i = 0; i < mGraph.vNums; i++) {
int minWeight = Integer.MAX_VALUE;//最小的权值
int j = 1;
int k = 0;//最小的权值结点下标
//遍历所有的结点
while(j<mGraph.vNums){
//找到集合外相邻边权值最小的一条
if(lowcost[j]!=0&&lowcost[j]<minWeight){
minWeight = lowcost[j];
//将发现的最小权值的下标存入k,以便使用
k = j;
}
j++;
}
System.out.println(" " + adjvex[k] + k);//连接当前最小权值结点的相关顶点
//加入新的结点后
lowcost[k] = 0;
// 更新一遍集合相邻最小权值
for (j = 1;j<mGraph.vNums;j++){
if(lowcost[j]!=0&&mGraph.arcs[k][j]<lowcost[j]){
lowcost[j] = mGraph.arcs[k][j];
adjvex[j] = k;//连接集合相邻最小权值结点的结点
}
}
}
}
}