简单实现最小生成树-Prim算法

今天看了一篇非常好的文章  http://blog.chinaunix.net/uid-25324849-id-2182922.html

讲解最小生成树的Prim和Kruskal算法, 看了之后, 感觉初步明白了算法的思想和流程

这里简单实现一下Prim算法, 留作笔记

          输入: 第一行输入顶点的个数v和边的条数v,  随后v行依次输入编号为i的顶点到编号为j的顶的距离d

          找出一条路径和最小的路径, 使得v个顶点之间都能连通(不需要直接相连),输出路径的长度, 如果不能找到这样的路径输出-1


package algorithm.mst;

import java.io.BufferedInputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Scanner;

public class Prim {

	public static void main(String[] args) {
		Scanner cin = new Scanner(new BufferedInputStream(System.in));
		
		int vertexCount = cin.nextInt();
		int edge = cin.nextInt();
		
		Map<Integer, Vertex> map = new HashMap<Integer, Vertex>();
		for(int i=0; i<edge; i++) {
			int current = cin.nextInt();
			int adjacent = cin.nextInt();
			int distance = cin.nextInt();
			
			Vertex vertex = map.get(current);
			if(vertex == null) {
				vertex = new Vertex(current);
				map.put(current, vertex);
			}
			vertex.adjacent.put(adjacent, distance);
			
			Vertex node = map.get(adjacent);
			if(node == null) {
				node = new Vertex(adjacent);
				map.put(adjacent, node);
			}
			node.adjacent.put(current, distance);
		}
		
		System.out.println(prim(map, vertexCount));
		
		cin.close();
	}
	
	/**
	 * 	
	 * 	算法思路
	 * 		初始化
	 * 			将所有点标记为未访问
	 * 			任选一点作为开始, 并将该点标记的访问
	 *      1. 找出所有连接已访问的结点和未访问节点的边
	 *      2. 在这些边中选择路径最短的边, 并且将这条边中未访问的那个端点标记为访问
	 *      3. 重复循环到1, 直到1选出的边集合为空
	 *      
	 *      这里只要输入的图是连通图, 那么2中选出来的边的集合构成的树就是最小生成树
	 */
	static int prim(Map<Integer, Vertex> vertexs, int vertexCount) {
		List<Vertex> select = new ArrayList<Vertex>(vertexs.size());
		int startId = vertexs.entrySet().iterator().next().getKey();
		select.add(vertexs.remove(startId));

		int sum = 0;
		Edge edge = null;
		while((edge = extraEdge(select, vertexs)) != null) {
			sum += edge.distance;
		}
		return select.size() == vertexCount ? sum : -1;
	}
	
	private static Edge extraEdge(List<Vertex> select, Map<Integer, Vertex> remain) {
		Edge edge = null;
		for(Vertex s : select) {
			for(Vertex v : remain.values()) {
				if(s.adjacent.containsKey(v.id)) {
					int d = s.adjacent.get(v.id);
					if(edge == null) {
						edge = new Edge(s.id, v.id, d);
					} else {
						if(d < edge.distance) {
							edge = new Edge(s.id, v.id, d);
						}
					}
				}
			}
		}
		if(edge != null) {
			select.add(remain.remove(edge.target));
		} 
		return edge;
	} 
}

class Vertex {
	int id;
	Map<Integer, Integer> adjacent = new HashMap<Integer, Integer>();
	
	Vertex(int current) {
		id = current;
	}
}

class Edge {
	int source;
	int target;
	int distance;
	
	@Override
	public String toString() {
		return "[" + source + ", " + target + ", " + distance + "]";
	}
	
	public Edge(int s, int t, int d) {
		this.source = s;
		this.target = t;
		this.distance = d;
	}
}


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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值