例题: AcWing 859、kruskal
1、kruskal
思想:将边从小到大排序,每次判断这条边的两个节点是否已经联通,如果没有联通的话就把这条边加入。
import java.util.*;
public class Main{
static int par[];
static int find(int x){
int root=x;
//找到x的祖父节点【最上面的节点】
while(root!=par[root]) root=par[root];
while(root!=x){
//修改x上面的节点,将他们的祖父节点指向root
int t=par[x];
par[x]=root;
x=t;
}
return root;
}
static void union(int x,int y){
x=find(x);
y=find(y);
if(x!=y){
par[x]=y;
}
}
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
par=new int[n];
for(int i=0;i<n;i++)
par[i]=i;
int[][] edges=new int[m][3];
for(int i=0;i<m;i++){
edges[i][0]=sc.nextInt()-1;
edges[i][1]=sc.nextInt()-1;
edges[i][2]=sc.nextInt();
}
Arrays.sort(edges,(o1,o2)->o1[2]-o2[2]);
int ans=0,nEdge=0;
for(int[] edge:edges){
int from=edge[0],to=edge[1],val=edge[2];
if(find(from)!=find(to)){
union(from,to);
ans+=val;
nEdge++;
}
}
if(nEdge<n-1){
System.out.println("impossible");
}else{
System.out.println(ans);
}
}
}
2、prim
思想:跟dijkstra差不多,根据当前已经更新的节点去延伸,将边加入到集合中
import java.util.*;
public class Main{
public static void main(String[] args){
Scanner sc=new Scanner(System.in);
int n=sc.nextInt(),m=sc.nextInt();
int[] dist=new int[n];
int[][] g=new int[n][n];
int ans=0,max=Integer.MAX_VALUE/2;
boolean[] vis=new boolean[n];
Arrays.fill(dist,max);
for(int i=0;i<n;i++)
Arrays.fill(g[i],max);
for(int i=0;i<m;i++){
int a=sc.nextInt()-1;
int b=sc.nextInt()-1;
int c=sc.nextInt();
g[a][b]=Math.min(g[a][b],c);
g[b][a]=g[a][b];
}
dist[0]=0;
for(int i=0;i<n;i++){
int t=-1,min=max;
for(int j=0;j<n;j++){
if(!vis[j]&&dist[j]<min){
t=j;
min=dist[j];
}
}
//没有其它联通的点了
if(t==-1){
System.out.println("impossible");
return ;
}
ans+=dist[t];
vis[t]=true;
for(int j=0;j<n;j++){
if(!vis[j]&&g[t][j]<dist[j]){
dist[j]=g[t][j];
}
}
}
System.out.println(ans);
}
}