稀疏图中使用Kruskal算法进行。
思路
- 将所有边按权重从小到大排序(快排)( O ( m l o g m ) O(mlogm) O(mlogm))
- 枚举每条边a->b 权重为c,如果a和b不连通,就将这条边加到集合中,相当于是在a,b之间加一条边。 ( O ( m ) O(m) O(m))
题目
例1:Acwing 859
给定一个 n 个点 m条边的无向图,图中可能存在重边和自环,边权可能为负数。
求最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible。
给定一张边带权的无向图 G = ( V , E ) G=(V,E) G=(V,E),其中 V 表示图中点的集合,E 表示图中边的集合, n = ∣ V ∣ n=|V| n=∣V∣, m = ∣ E ∣ m=|E| m=∣E∣。
由 V 中的全部 n 个顶点和 E中 n−1 条边构成的无向连通子图被称为 G的一棵生成树,
其中边的权值之和最小的生成树被称为无向图 G 的最小生成树。
输入格式
第一行包含两个整数 n和 m。
接下来 m 行,每行包含三个整数 u,v,w,表示点 u和点 v之间存在一条权值为 w 的边。
输出格式
共一行,若存在最小生成树,则输出一个整数,表示最小生成树的树边权重之和,如果最小生成树不存在则输出 impossible
。
数据范围
1
≤
n
≤
1
0
5
1≤n≤10^5
1≤n≤105,
1
≤
m
≤
2
∗
1
0
5
1≤m≤2*10^5
1≤m≤2∗105,
图中涉及边的边权的绝对值均不超过 1000。
输入样例:
4 5
1 2 1
1 3 2
1 4 3
2 3 2
3 4 4
输出样例:
6
#include<bits/stdc++.h>
using namespace std;
// n表示的是顶点数目,m表示的是边数
int n,m;
const int N = 1e5+10;
const int M = 2e5+10;
// 并查集
int p[N];
struct Node{
int from;
int to;
int val;
}edges[M];
bool cmp(const Node& a,const Node& b){
return a.val < b.val;
}
int find(int x){
if(p[x]!=x)
p[x] = find(p[x]);
else
return p[x];
}
int main(){
std::ios::sync_with_stdio(false);
cin.tie(nullptr);
// 输入
cin>>n>>m;
for(int i = 0;i<m;i++){
cin>>edges[i].from>>edges[i].to>>edges[i].val;
}
// 排序
sort(edges,edges+m,cmp);
// 初始化并查集
for(int i = 1;i<=n;i++){
p[i] = i;
}
int res = 0,cnt = 0;
// 从小到大枚举所有的边
for(int i = 0;i<m;i++){
int a = edges[i].from , b = edges[i].to , val = edges[i].val;
a = find(a),b = find(b);
// 表示a,b之间之前没有连通的点的话
if(a != b){
p[a] = b;
res += val;
cnt++;
}
}
if(cnt < n-1){
cout<<"impossible"<<endl;
}else{
cout<<res<<endl;
}
return 0;
}
import java.util.Scanner;
import java.util.*;
class Main{
private int n;
private int m;
private static final int N = 100010;
// 声明父集合
private static int[] p = new int[N];
private static class Edge implements Comparable<Edge>{
private int a;
private int b;
private int val;
Edge(int a, int b, int val) {
this.a = a;
this.b = b;
this.val = val;
}
int getA(){
return this.a;
}
int getB(){
return this.b;
}
int getVal(){
return this.val;
}
@Override
public int compareTo(Edge other){
return Integer.compare(this.val,other.val);
}
}
private static int find(int a){
if(p[a] != a){
p[a] = find(p[a]);
}
return p[a];
}
public static void main(String[] args){
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
Edge[] edges = new Edge[m];
for(int i = 0;i<m;i++){
int a = sc.nextInt();
int b = sc.nextInt();
int val = sc.nextInt();
edges[i] = new Edge(a, b, val);
}
Arrays.sort(edges);
// 初始化父集合
for(int i = 1;i<=n;i++){
p[i] = i;
}
int res = 0;
int cnt = 0;
for(int i = 0;i<m;i++){
int a = edges[i].getA();
int b = edges[i].getB();
int val = edges[i].getVal();
a = find(a);
b = find(b);
if(a != b){
p[a] = b;
res += val;
cnt ++;
}
}
if(cnt<n-1){
System.out.println("impossible");
}else{
System.out.println(res);
}
sc.close();
}
}