您的位置:首页 > 其它

最小生成树(Prim)(普利姆最小生成树)

2016-10-06 20:54 176 查看
import java.io.File;
import java.io.FileNotFoundException;
import java.util.Arrays;
import java.util.LinkedList;
import java.util.Scanner;

import com.sun.corba.se.impl.oa.poa.ActiveObjectMap.Key;
import com.sun.scenario.effect.impl.prism.PrImage;

public class Test {

 static Vertex[] v;
// 就是用于记录用户要输入多少条边关系的,其他没什么╮(╯▽╰)╭
 static int mark = 0;
 static int sum = 0;
 static int[] dis;
 static int key;
 static final int MINVAL = 9999999;
 static int min = MINVAL;
// 用于记录这个顶点是否已经选择过了
 static int[] book;

 public static void main(String[] args) throws FileNotFoundException {
  Scanner scanner = new Scanner(System.in);

  v = new Vertex[scanner.nextInt() + 1];
  dis = new int[v.length];
  book = new int[v.length];
  mark = scanner.nextInt();
 
  for (int i = 0; i < v.length; i++) {
   v[i] = new Vertex();
   // 不过从哪个点开始,一开始默认所有的距离都是MINVAL
   dis[i] = min;
  }
 
 
  int temp1 = 0;
  int temp2 = 0;
  int temp3 = 0;
  Edge edge = null;

  for (int i = 0; i < mark; i++) {
   temp1 = scanner.nextInt();
   temp2 = scanner.nextInt();
   temp3 = scanner.nextInt();

   edge = new Edge(temp1, temp2, temp3);
   v[temp1].getEdges().add(0, edge);
   edge = new Edge(temp2, temp1, temp3);
   v[temp2].getEdges().add(0, edge);
  }
 
  // 假定从1号顶点开始扩展生成树
  book[1] = 1;
  temp1 = v[1].getEdges().size();
  for (int i = 0; i < temp1; i++) {
   edge = v[1].getEdges().get(i);
   dis[edge.getEnd()] = edge.getWeight();
  }
 
  prim();
 
  System.out.println(sum);
 
  scanner.close();
 }

 private static void prim() {
  int count = 0;
 
  while(true){
   min = MINVAL;
   // 先选取出dis中的最小值,这个就是当前最好的顶点,用它来做下一轮的中间点
   for (int i = 0; i < dis.length; i++) {
    if (book[i] == 0 && min > dis[i]) {
     min = dis[i];
     key = i;
    }
   }
   
   book[key] = 1;
   sum += min;
   count++;
   // 本来是应该减1的,但是因为从下标从1开始的关系,所以这里要减2
   if (count == v.length - 2) {
    break;
   }
   // 以中间点为拓展,开始展开下一步的“松弛”
   LinkedList<Edge> edges = v[key].getEdges();
   Edge edge;
   
   for (int i = 0; i < edges.size(); i++) {
    edge = edges.get(i);
// 需要注意的是,这里的book[edge.getEnd()] == 0非常重要,这是为了保证不形成回路的根本。
// 因为当book[edge.getEnd()] == 1时,表明前边已经加其加入生成树之中了,它已经做过中转点了。
// 然后需要注意的就是edge.getWeight() < dis[edge.getEnd()],这里之所以这样写,有两个方面的原因吧。
// 第一个原因:因为dis这时候记录的是下一个可能的中转点到这棵生成树里面每一个节点的距离,所以这样写即可
// 而不是像迪杰斯特拉一样,需要dis[xx] + edge.getWeight() < dis[xxx]这种形式
// 第二个原因嘛:就是注意edge.getEnd()这里不要写成edge.getBegin了,这样的话,你不断改变的都是这是一个地方的dis值
// 而且这个dis的值已经被book【xx】所阻挡了= =
   if (book[edge.getEnd()] == 0 && edge.getWeight() < dis[edge.getEnd()]) {
     dis[edge.getEnd()] = edge.getWeight();
    }
   }
  }
 }
}

class Vertex {
 private LinkedList<Edge> edges = new LinkedList<>();
 private int id;

 public Vertex() {

 }

 public LinkedList<Edge> getEdges() {
  return edges;
 }

 public void setEdges(LinkedList<Edge> edges) {
  this.edges = edges;
 }

 public int getId() {
  return id;
 }

 public void setId(int id) {
  this.id = id;
 }

}

class Edge implements Comparable<Edge> {
 private int begin;
 private int end;
 private int weight;

 public Edge() {

 }

 public Edge(int begin, int end, int weight) {
  this.begin = begin;
  this.end = end;
  this.weight = weight;
 }

 public int getBegin() {
  return begin;
 }

 public void setBegin(int begin) {
  this.begin = begin;
 }

 public int getEnd() {
  return end;
 }

 public void setEnd(int end) {
  this.end = end;
 }

 public int getWeight() {
  return weight;
 }

 public void setWeight(int weight) {
  this.weight = weight;
 }

 @Override
 public String toString() {
  return "Edge [begin=" + begin + ", end=" + end + ", weight=" + weight
    + "]";
 }

 @Override
 public int compareTo(Edge o) {
  if (this.weight > o.getWeight()) {
   return 1;
  }
  return -1;
 }

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: