定义不多说,说说代码的实现。
用落谷上的题目来说明代码的正确性
落谷上的题目
邻接矩阵的实现
定义一个生成树点的集合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。。。真是服了。但结果保证正确)
这个实现容易理解,也很容易实现。
在加权无向图中,选择一个起点
- 把起点的邻边全部加入到优先队列中。
- 取出队列的头部元素,这个边p的权重目前是最小的。
- 将这个p对应的顶点w加入到生成树里面
- 将w的邻边全部加入到优先队里
- 取出头部元素…
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);
}
}
}
}