洛谷 P2872 Building Roads S
这道题其实也是最小生成树的模板题,本人是用 prim 算法做的,题目给的是每个点的坐标,所以用两点的距离公式算出每两个点的距离,然后给每两个点都添加上边,因为题目有一些边已经连上了,所以再给图加上这些边(距离为 0),最后直接算最小生成树的边的和(weight 为 0 的边不影响结果)。
package 图论;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.StreamTokenizer;
import java.util.ArrayDeque;
import java.util.ArrayList;
import java.util.PriorityQueue;
// 建边
class Edge implements Comparable<Edge> {
int v;
int w;
double weight;
public Edge(int v, int w, double weight) {
this.v = v;
this.w = w;
this.weight = weight;
}
int either() {
return v;
}
int other(int v) {
if (this.v == v) {
return w;
}
return this.v;
}
@Override
public int compareTo(Edge o) {
return Double.compare(this.weight, o.weight);
}
}
// 建图
class EdgeWeightedGraph {
int v;
ArrayList[] adj;
public EdgeWeightedGraph(int v) {
this.v = v;
adj = new ArrayList[v];
for (int i = 0; i < v; i++) {
adj[i] = new ArrayList();
}
}
void addEdge(int v, int w, double weight) {
Edge e = new Edge(v, w, weight);
adj[v].add(e);
adj[w].add(e);
}
}
class LazyPrim {
boolean[] marked;
PriorityQueue<Edge> pq;
ArrayDeque<Edge> queue;
int v;
public LazyPrim(EdgeWeightedGraph G) {
this.v = G.v;
marked = new boolean[v];
pq = new PriorityQueue<>();
queue = new ArrayDeque<>();
visit(G, 0);
while (! pq.isEmpty()) {
Edge e = pq.poll();
int v = e.either();
int w = e.other(v);
if (marked[v] == true && marked[w] == true) {
continue;
}
queue.add(e);
if (marked[v] == false) {
visit(G, v);
}
if (marked[w] == false) {
visit(G, w);
}
}
}
void visit(EdgeWeightedGraph G, int v) {
marked[v] = true;
for (Object o : G.adj[v]) {
Edge e = (Edge)o;
int w = e.other(v);
if (marked[w] == false) {
pq.offer(e);
}
}
}
}
/**
* @author wangshaoyu
*/
public class P2872BuildingRoads {
static BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
static StreamTokenizer st = new StreamTokenizer(br);
static int nextInt() throws IOException {
st.nextToken();
return (int) st.nval;
}
static double nextDouble() throws IOException {
st.nextToken();
return st.nval;
}
public static void main(String[] args) throws IOException {
int n = nextInt(); // 点数
int m = nextInt(); // 边数
EdgeWeightedGraph G = new EdgeWeightedGraph(n);
int[][] xy = new int[n][2]; // 点的坐标
for (int i = 0; i < n; i++) {
xy[i][0] = nextInt();
xy[i][1] = nextInt();
}
// 已经存在的边初始化为 0
for (int i = 0; i < m; i++) {
int v = nextInt() - 1;
int w = nextInt() - 1;
G.addEdge(v, w, 0);
}
// 每两个点添加一条边
for (int i = 0; i < n; i++) {
for (int j = i + 1; j < n; j++) {
double weight = Math.sqrt(Math.pow((xy[i][0] - xy[j][0]), 2) + Math.pow((xy[i][1] - xy[j][1]), 2));
G.addEdge(i, j, weight);
}
}
LazyPrim lp = new LazyPrim(G);
double ans = 0;
for (Edge e : lp.queue) {
ans += e.weight;
}
System.out.printf("%.2f\n", ans);
}
}