航海家们在太平洋上发现了几座新岛屿,其中最大的一个岛已经连接到Internet,但是其它岛和主岛之间没有电缆连接,所以无法入网。我们的目的是让所有岛上的居民都能上网,即每个岛和主岛之间都有直接或间接的电缆连接。输入每两个岛屿之间的连接成本,要求给出最节省成本的方案。
先输入点的数量n,边的数量m,然后输入m行数据,每行数据包括起点u,终点v,成本weight,最后输出最优方案所选的边;
样例输入:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
样例输出:
0 3 5
2 4 5
3 5 6
0 1 7
1 4 7
4 6 9
Kruskal算法
根据权值对边排序,每次选择权值最小的边,选择过程利用并查集判断一下是否为同一个连通分量,即防止形成环
import java.util.Arrays;
import java.util.Comparator;
import java.util.Scanner;
public class Main {
static class Edge {
int u;
int v;
int weight;
public Edge(int u, int v, int weight) {
this.u = u;
this.v = v;
this.weight = weight;
}
}
// 查找根节点
public static int find(int[] p, int x) {
if (p[x] == x)
return x;
else
return p[x] = find(p, p[x]);
}
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 u = sc.nextInt();
int v = sc.nextInt();
int weight = sc.nextInt();
edges[i] = new Edge(u, v, weight);
}
Arrays.sort(edges, new Comparator<Edge>() {
@Override
public int compare(Edge o1, Edge o2) {
return o1.weight - o2.weight;
}
});
int[] p = new int[n];
for (int i = 0; i < n; i++) {
p[i] = i;
}
for (int i = 0; i < m; i++) {
int x = find(p, edges[i].u);
int y = find(p, edges[i].v);
// 判断是否为一个连通分量,防止形成环
if (x == y)
continue;
else {
// 合并连通分量
p[x] = y;
System.out.println(edges[i].u + " " + edges[i].v + " " + edges[i].weight);
}
}
}
}
Prim算法求最小生成树总权值
构造点的集合,dis[ i ]存点i到其余点的最小权值,每次都会更新,假设从0点开始,就把点0加入集合,选0到其余点的最小权值,循环n次选出n个点,其中把最小生成树权值都加起来
先输入点的数量n,边的数量m,然后输入m行数据,每行数据包括起点u,终点v,成本weight,最后输出最小生成树的总权值。
样例输入:
7 11
0 1 7
0 3 5
1 2 8
1 3 9
1 4 7
2 4 5
3 4 15
3 5 6
4 5 8
4 6 9
5 6 11
样例输出:
39
import java.util.Arrays;
import java.util.Scanner;
public class Main {
static class Edge {
int u;
int v;
int weight;
public Edge(int u, int v, int weight) {
this.u = u;
this.v = v;
this.weight = weight;
}
}
public static void main(String[] args) {
Scanner sc = new Scanner(System.in);
int n = sc.nextInt();
int m = sc.nextInt();
int[][] edges = new int[n][n];
for (int i = 0; i < m; i++) {
int u = sc.nextInt();
int v = sc.nextInt();
int weight = sc.nextInt();
edges[u][v] = weight;
edges[v][u] = weight;
}
// dis[i]表示存放结点i到已访问结点的最小权值
int[] dis = new int[n];
int[] vis = new int[n];// 标记数组
Arrays.fill(dis, Integer.MAX_VALUE);
dis[0] = 0;
int res = 0;
for (int i = 0; i < n; i++) {
int x = -1;
int min = Integer.MAX_VALUE;
for (int j = 0; j < n; j++) {
if (vis[j] == 0 && dis[j] < min) {
x = j;
min = dis[j];
}
}
res += min;
vis[x] = 1;
// 更新选中点到其它点的dis值
for (int k = 0; k < n; k++) {
if (vis[k] == 0 && edges[x][k] > 0) {
if (dis[k] > edges[x][k]) {
dis[k] = edges[x][k];
}
}
}
}
System.out.println(res);
}
}
参考博客【java】最小生成树