53.寻宝(第七期模拟笔试)
题目描述
在世界的某个区域,有一些分散的神秘岛屿,每个岛屿上都有一种珍稀的资源或者宝藏。国王打算在这些岛屿上建公路,方便运输。不同岛屿之间,路途距离不同,国王希望你可以规划建公路的方案,如何可以以最短的总公路距离将 所有岛屿联通起来(注意:这是一个无向图)。
给定一张地图,其中包括了所有的岛屿,以及它们之间的距离。以最小化公路建设长度,确保可以链接到所有岛屿。
输入描述
第一行包含两个整数V 和 E,V代表顶点数,E代表边数 。顶点编号是从1到V。例如:V=2,一个有两个顶点,分别是1和2。
接下来共有 E 行,每行三个整数 v1,v2 和 val,v1 和 v2 为边的起点和终点,val代表边的权值。
输出描述
输出联通所有岛屿的最小路径总距离
输入示例
7 11
1 2 1
1 3 1
1 5 2
2 6 1
2 4 2
2 3 2
3 4 1
4 5 1
5 6 2
5 7 1
6 7 1
输出示例
6
提示信息
数据范围:
2 <= V <= 10000;
1 <= E <= 100000;
0 <= val <= 10000;如下图,可见将所有的顶点都访问一遍,总距离最低是6.
解题思路
prime解法
核心思想是以节点为准,查找相关的权值最小的边。自己起初用邻接矩阵写的,遍历要遍历N^2。
import java.util.*;
class Main {
public static int prime(int[][] graph, boolean[] visited) {
int min = Integer.MAX_VALUE;
int choose = -1;
for (int i = 0; i < graph.length; i++) {
if (!visited[i]) {
continue;
}
for (int j = 0; j < graph.length; j++) {
if (!visited[j] && graph[i][j] > 0) {
if (min > graph[i][j]) {
min = graph[i][j];
choose = j;
}
}
}
}
if (choose == -1) {
return 0;
}
visited[choose] = true;
return prime(graph, visited) + min;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int v = in.nextInt(), e = in.nextInt();
int[][] graph = new int[v][v];
for (int i = 0; i < e; i++) {
int v1 = in.nextInt() - 1;
int v2 = in.nextInt() - 1;
int val = in.nextInt();
graph[v1][v2] = val;
graph[v2][v1] = val;
}
in.close();
boolean[] visited = new boolean[v];
visited[0] = true;
int ans = prime(graph, visited);
System.out.println(ans);
}
}
邻接表优化思路
使用邻接表+优先队列的方式,将起始点有关的边加入进去。然后维护这个优先队列,每次取堆顶就行了。直到所有顶点都已经被访问。
import java.util.*;
class Main {
static class Edge {
int to, val;
Edge(int to, int val) {
this.to = to;
this.val = val;
}
}
public static int prime(List<Edge>[] graph, int n) {
boolean[] visited = new boolean[n];
PriorityQueue<Edge> pq = new PriorityQueue<>(Comparator.comparingInt(e -> e.val));
visited[0] = true;
for (Edge e : graph[0]) {
pq.offer(e);
}
int ans = 0, cnt = 1;
while (!pq.isEmpty() && cnt < n) {
Edge cur = pq.poll();
if (visited[cur.to]) {
continue;
}
visited[cur.to] = true;
ans += cur.val;
cnt++;
for (Edge next : graph[cur.to]) {
if (!visited[next.to]) {
pq.offer(next);
}
}
}
// 图不连通则不存在最小生成树
if (cnt < n) {
throw new RuntimeException("图不连通,最小生成树不存在");
}
return ans;
}
static List<Edge>[] constructGraph() {
Scanner in = new Scanner(System.in);
int v = in.nextInt(), e = in.nextInt();
List<Edge>[] graph = new ArrayList[v];
for (int i = 0; i < v; i++) {
graph[i] = new ArrayList<>();
}
for (int i = 0; i < e; i++) {
int v1 = in.nextInt() - 1;
int v2 = in.nextInt() - 1;
int val = in.nextInt();
graph[v1].add(new Edge(v2, val));
graph[v2].add(new Edge(v1, val));
}
in.close();
return graph;
}
public static void main(String[] args) {
List<Edge>[] graph = constructGraph();
int v = graph.length;
int ans = prime(graph, v);
System.out.println(ans);
}
}
Kruskal解法
import java.util.*;
class Main {
static class Edge {
int v, u, val;
Edge(int v, int u, int val) {
this.v = v;
this.u = u;
this.val = val;
}
}
static class DSU {
int[] father;
DSU(int n) {
father = new int[n];
for (int i = 0; i < n; i++) {
father[i] = i;
}
}
int find(int x) {
return father[x] == x ? x : (father[x] = find(father[x]));
}
boolean union(int a, int b) {
int ra = find(a);
int rb = find(b);
if (ra == rb) {
return false;
}
father[ra] = rb;
return true;
}
}
public static int kruskal(List<Edge> edges, int n) {
Collections.sort(edges, Comparator.comparingInt(e -> e.val));
DSU dsu = new DSU(n);
int ans = 0, cnt = 0;
for (Edge edge : edges) {
if (dsu.union(edge.v, edge.u)) {
ans += edge.val;
cnt++;
if (cnt == n - 1) break;
}
}
return ans;
}
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
int v = in.nextInt(), e = in.nextInt();
List<Edge> edges = new ArrayList<>();
for (int i = 0; i < e; i++) {
int v1 = in.nextInt() - 1;
int v2 = in.nextInt() - 1;
int val = in.nextInt();
edges.add(new Edge(v1, v2, val));
edges.add(new Edge(v2, v1, val));
}
in.close();
int ans = kruskal(edges, v);
System.out.println(ans);
}
}

评论