Java实现Prim最小生成树算法

引入

随手笔记,以防忘记,写得不好,请见谅

  • 个人理解
  1. 每次取出哪个点到已生成树的最短距离的点
  2. 以该点进行扩散,访问它的邻接点
  3. 若扩散点到新点的距离 < 新点到生成树的距离,更新新点到生成树的距离
  4. 如此循环
  • 补充
    Prim算法和Dijkstra算法有些类似,不同的是
  1. Prim每次是取出未收入的点(未标记访问完成的点)到已生成树的最短距离的点,以该点来扩散,得到该点的邻接点更新到已生成树的距离
dist[j] = G[minp][j];

新点到生成树距离=扩散点到新点的距离

  1. Dijkstra是取出源点到其它点最短距离的点,以该点来扩散,得到该点的领接点来更新源点到该点的邻接点的距离
dis[j] = dis[u] + G[u][j]

源点到新点=源点到扩散点+扩散点到新点

代码

  1. 用邻接矩阵的实现:
import java.util.Scanner;

public class C2Prime {
	static int dist[];// 每个点到树的距离
	static boolean visit[];// 是否访问
	static int G[][];// 领接矩阵
	static int N;// N个顶点
	static int E;// E条边
	static int path[];// 记录路线
	// 具体执行方法
	public static void prime(int sourcepoint){
		// 初始化路径,其它点默认从源点到达
		for(int i = 1; i <= N; i++){
			path[i] = sourcepoint;
		}
		// 初始化dist,根据sourcepoint
		for(int i = 1; i <= N; i++){
			dist[i] = G[sourcepoint][i];
		}
		// 给源点标记,因为从这个源点出发
		dist[sourcepoint] = 0;// 最小
		path[sourcepoint] = -1;// 源点出发为-1
		// 生成树的边值总和
		int sum = 0;
		// 每次找的最小点
		int minp;
		// 最小边
		int mine;
		// 外层循环是N个点
		for(int i = 1; i <= N; i++){
			minp = -1;
			mine = Integer.MAX_VALUE;
			// 1.循环找出到已生成的树的最小边的点
			for(int j = 1; j <= N; j++){
				// 没有访问过 ,和最小的边
				if(!visit[j] && dist[j] < mine){
					mine = dist[j];
					minp = j;
				}
			}
			// 没找到退出
			if(minp == -1){
				break;
			}
			// 2.标记访问过
			visit[minp] = true;
			// 累计加上边值
			sum += mine;
			// 3.由minp点到其它点来更新dist值,每个点到已有的树的最小值
			for(int j = 1; j <= N; j++){
				// 没有访问过j点并且j点可达
				if(!visit[j] && G[minp][j] != Integer.MAX_VALUE){
					if(G[minp][j] < dist[j]){
						// 更新值
						dist[j] = G[minp][j];
						// 保存路径
						path[j] = minp;
					}
				}
			}
		}
		// 打印总和
		System.out.println("路径总和:"+sum);
	}
	// 打印路径
	public static void printPath(int u){
		// 如果是0代表到达起点
		if(path[u] == -1){
			System.out.print("路径:"+u+"->");
		}else{
			// 上一层
			printPath(path[u]);
			// 递归结束,打印路径
			System.out.print(u+"->");
		}
	}
	public static void main(String[] args) {
		Scanner sc = new Scanner(System.in);
		// 点,边
		N = sc.nextInt();
		E = sc.nextInt();
		// 初始化
		G = new int[N + 1][N + 1];
		dist = new int[N + 1];
		visit = new boolean[N + 1];
		path = new int[N + 1];
		
		// 图初始化为最大值
		for(int i = 1; i <= N ; i++){
			for(int j = 1; j <= N ; j++){
				G[i][j] = Integer.MAX_VALUE;
			}
		}
		
		int u, v, e;//点u到v点的e边
		for(int i = 0; i < E; i++){
			u = sc.nextInt();
			v = sc.nextInt();
			e = sc.nextInt();
			G[u][v] = e;
			G[v][u] = e;// 无向图
		}
		// prim
		int sourcepoint = 1;// 源点出发
		prime(sourcepoint);// 执行
		
		for(int i = 1; i <= N; i++){
			// 打印路径
			if(sourcepoint != i){
				System.out.print("生成点:"+i+"的路径是:");
				printPath(i);
				System.out.println();
			}
		}
		
		sc.close();
	}
}
  1. 输入数据
    6 10
    1 2 6
    3 1 1
    1 4 5
    2 3 5
    2 5 3
    3 4 5
    3 5 6
    3 6 4
    4 6 2
    5 6 6

  2. 输出数据
    在这里插入图片描述

  3. 手绘生成树过程
    在这里插入图片描述

  • 4
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

刘建杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值