相关名词
- 连通图(无向图): 在无向图中,若任意两个顶点Vi与Vj都有路径相通,则称该无向图为连通图。
- 强连通图(有向图): 有向图中,若任意两个顶点Vi与Vj都有路径相通,则称该有向图为强连通图。
- 生成树: 含有图中全部n个顶点的一个连通子图,只有足以构成一棵树的n-1条边。即若生成树中再添加一条边,则必定成环。
- 最小生成树: 在连通网的所有生成树中,所有边的代价和最小的生成树,称为最小生成树。
最小生成树算法
Prim算法(加点法)
每次迭代选择代价最小的边对应的点,加入到最小生成树中。算法从某一个顶点s开始,最小生成树不唯一。
**输入:**邻接矩阵,使用List存放已经被加入生成树的点,sum计算总权值
使用数组parent存放每个节点加入生成树时的父节点,初始化为-1,根节点为0;
**输出:**sum
-
起点为任意一点,首先放入list中
-
list中不包含所有节点时
1)遍历list,找出所有能连通非List中节点的最小权重的边并加入list中
2)更新list及parent数组的对应值
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
| import java.util.ArrayList; import java.util.Arrays; import java.util.List; import java.util.Scanner;
public class Prim { public static int[][] axis = new int[1000][2]; public static int[][] dis = new int[1000][1000]; public static int n; public static void main(String[] args){ Scanner sc= new Scanner(System.in); n = sc.nextInt(); for(int i=0;i<n;i++){ int x = sc.nextInt(); int y = sc.nextInt(); axis[i] = new int[]{x,y}; } for(int i =0;i<n;i++){ for(int j=0;j<n;j++){ if(i==j){ dis[i][j]=-1; } else{ dis[i][j]= (int) Math.sqrt(Math.pow(axis[i][1]-axis[j][1],2) +Math.pow(axis[i][0]-axis[j][0],2)); } } } sc.close(); Generate(); } public static void Generate(){ List<Integer> list = new ArrayList<>(); list.add(0); int sum = 0; int[] parent = new int[n]; for(int i=0;i<n;i++){ parent[i]=-1; } int weight = 0; int begin=0, end=0; while(list.size()<n){ weight = Integer.MAX_VALUE; for(Integer row: list){
for(int i=0;i<n;i++){ if(!list.contains(i)){ if(dis[row][i]>0 && dis[row][i]<weight){ begin =row; end = i; weight = dis[row][i]; } } } }
list.add(end); parent[end] = begin; sum+= weight; } System.out.println(Arrays.toString(parent)); System.out.println(sum); } }
|
Kruskal 算法(加边法)
- 将图中所有边按照权值大小排序;
- 按权值从小到大选择边,要求所选边连接的两个顶点必须属于不同的树(利用parent记录各节点所在树的根节点,即要求两节点的根节点不相同→不在同一棵树
- 需要构造一个三元组Edge<begin,end,weight>来表示各条边,存入List中按照weight进行排序,然后依次判断是否符合2中的条件要求(即判断begin和end的根节点是否不相同,根节点通过parent数组进行储存)
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103
| import java.util.*;
class Edge implements Comparable<Edge>{ private int begin; private int end; private int weight;
public Edge(int begin, int end, int weight) { this.begin = begin; this.end = end; this.weight = weight; }
public int getBegin() { return begin; }
public int getEnd() { return end; }
public int getWeight() { return weight; }
@Override public int compareTo(Edge o){ if(o.weight >this.weight){ return -1; }else{ return 1; } } } public class Kruskal { public static int[][] axis = new int[1000][2]; public static int[][] dis = new int[1000][1000]; public static int n; public static void main(String[] args){ Scanner sc= new Scanner(System.in); n = sc.nextInt(); for(int i=0;i<n;i++){ int x = sc.nextInt(); int y = sc.nextInt(); axis[i] = new int[]{x,y}; } for(int i =0;i<n;i++){ for(int j=0;j<n;j++){ if(i==j){ dis[i][j]=-1; } else{ dis[i][j]= (int) Math.sqrt(Math.pow(axis[i][1]-axis[j][1],2)+Math.pow(axis[i][0]-axis[j][0],2)); } } } sc.close(); List<Edge> list = new ArrayList<>();
for(int i=0;i<n;i++){ for(int j=i+1;j<n;j++){ if(dis[i][j]>=0){ list.add(new Edge(i,j,dis[i][j]));
} } }
Collections.sort(list);
int[] parent = new int[n]; for(int i=0;i<n;i++){ parent[i] = -1; } int m,k; int sum = 0; for(Edge edge:list){
m = find(edge.getBegin(),parent); k = find(edge.getEnd(),parent); if(m!=k){ parent[k]= m; sum+=edge.getWeight(); } } System.out.println(Arrays.toString(parent)); System.out.println(sum); }
public static int find(int ch,int[] parent) { while (parent[ch] >= 0) { ch = parent[ch]; } return ch; } }
|