小白都能看懂最小生成树prime算法

定义不多说,说说代码的实现。

用落谷上的题目来说明代码的正确性
落谷上的题目

邻接矩阵的实现

定义一个生成树点的集合A,和图中其他点 的集合B
先任意选择一个点a加入到A中,即visit[a]=true;
此时B中的点b到达生成树A的距离为dist[b]=G[a][b](因为此时生成树就一个点a)
然后选择最小的距离加入到A中,即在dist中选择最小的。
之后A中的点变多了,那我们要更新B到A的最新距离。
落谷上显示内存超了。。。。

import java.util.*;

class Jademo{
    
    
    public static void main(String[] args) {
    
    
        Scanner scanner = new Scanner(System.in);
        int n=scanner.nextInt();
        int eNum=scanner.nextInt();
        int dis[]=new int[n];//dis[i],点i  到生成树的最小距离
        int num[][]=new int[n][n];
        boolean visit[]=new boolean[n];
        for (int i = 0; i < n; i++) {
    
    
            Arrays.fill(num[i], Integer.MAX_VALUE);
        }
        for (int i = 0; i <eNum; i++) {
    
    
            int x,y,wei;
            x=scanner.nextInt();
            y=scanner.nextInt();
            wei= scanner.nextInt();
            x=x-1;
            y=y-1;
            if(num[x][y]>wei) {
    
    
                num[x][y] = wei;
                num[y][x] = wei;
            }
        }
        int s=0;
        for (int i = 0; i < n; i++) {
    
    
            dis[i]=num[s][i];
        }
        visit[s]=true;
        int ans=0;
        int index=0;
        for (int i = 1; i < n; i++) {
    
    //遍历所有的点。因为第一次初始化已经有了一个点了、
            int min=Integer.MAX_VALUE;
            for (int j = 0; j < n; j++) {
    
    //找到最小的dis,即其他点到生成树的最短距离
                if(dis[j]<min&&!visit[j]){
    
    
                    min=dis[j];
                    index=j;
                }
            }
            ans+=min;
            visit[index]=true;
            for (int j = 0; j < n; j++) {
    
     //生成树里的点变多了,可能有新的点可以到达了。需要更新
                if(dis[j]>num[index][j]&&!visit[j]){
    
    
                    dis[j]=num[index][j];
                }
            }
        }
        System.out.println(ans);
    }
}

邻接链表的实现

落谷上显示TLE。。。真是服了。但结果保证正确)

这个实现容易理解,也很容易实现。
在加权无向图中,选择一个起点

  1. 把起点的邻边全部加入到优先队列中。
  2. 取出队列的头部元素,这个边p的权重目前是最小的。
  3. 将这个p对应的顶点w加入到生成树里面
  4. 将w的邻边全部加入到优先队里
  5. 取出头部元素…
package Algorithm.WeightGraph;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.PriorityQueue;
import java.util.Scanner;
public class Prime {
    
    
    public static void main(String[] args) {
    
    
        int v,e;
        Scanner scanner = new Scanner(System.in);
        v=scanner.nextInt();
        e=scanner.nextInt();
        Graph1 graph1 = new Graph1(v,e);
        for (int i = 0; i < e; i++) {
    
    
            int a;
            int b;
            double wei;
            Edge1 edge1 = new Edge1(a=scanner.nextInt()-1,b=scanner.nextInt()-1,wei=scanner.nextDouble());
            if(graph1.graph[a][b]!=Double.POSITIVE_INFINITY&&wei>graph1.graph[a][b]){
    
    
                continue;
            }
            graph1.addEdge(edge1);
        }
        if(!graph1.isConnect()){
    
    
            System.out.println("orz");
            return;
        }
        System.out.println((int)graph1.prime());
    }

}
class Edge1 implements Comparable<Edge1>{
    
    
    int v;
    int w;
    double wei;
    public int compareTo(Edge1 e){
    
    
        if(this.wei<e.wei) return -1;
        if(this.wei>e.wei) return 1;
        return 0;
    }
    public Edge1(int v,int w,double wei){
    
    
        this.v=v;
        this.w=w;
        this.wei=wei;
    }
}

class Graph1{
    
    
    private int v;
    private int e;
    double[][] graph;
    private boolean[] marked;
    private ArrayList<Edge1> list;//保存生成树的边
    private PriorityQueue<Edge1> pq;//优先队列
    public Graph1(int v,int e){
    
    
        this.v=v;
        this.e=e;
        graph=new double[v][v];
        for (int i = 0; i < v; i++) {
    
    
            for (int j = 0; j < v; j++) {
    
    
                graph[i][j]=Double.POSITIVE_INFINITY;
            }
        }
        list=new ArrayList<>();
        pq=new PriorityQueue<>();
        marked=new boolean[v];
    }
    public Graph1(){
    
    }
    public void addEdge(Edge1 ed){
    
    
        int w=ed.w;
        int x=ed.v;
        double wei=ed.wei;
        graph[w][x]=wei;
        graph[x][w]=wei;
    }
    public double prime(){
    
    
        Arrays.fill(marked,false);
        double mstWei=0;
        visit(0);
        while (!pq.isEmpty()){
    
    
          Edge1 curEdge=pq.poll();
          if(marked[curEdge.w]&&marked[curEdge.v]) continue;
          mstWei+=curEdge.wei;
          if(!marked[curEdge.w]) visit(curEdge.w);
          if(!marked[curEdge.v]) visit(curEdge.v);
          list.add(curEdge);
        }
        return mstWei;
    }
    private void visit(int x){
    
    
        marked[x]=true;
        for (int i = 0; i <this.v; i++) {
    
    
            if(graph[x][i]!=Double.POSITIVE_INFINITY&&!marked[i]){
    
    
                pq.add(new Edge1(x,i,graph[x][i]));
            }
        }
    }
    
    public boolean isConnect(){
    
    //图是否连通
        int count=0;
        for (int i = 0; i < v; i++) {
    
    
            if(!marked[i]){
    
    
                dfs(i);
                count++;
            }
        }
        System.out.println(count);
        return count==1?true:false;
        //count可作为连通分量的判断。比如count=2,这个图两个连通分量
    }
    private void dfs(int v){
    
    
        marked[v]=true;
        for (int i = 0; i <this.v; i++) {
    
    
            if(!marked[i]&&graph[v][i]!=Double.POSITIVE_INFINITY){
    
    
                dfs(i);
            }
        }
    }
}

猜你喜欢

转载自blog.csdn.net/qq_43179428/article/details/108264300