๐Ÿ‘พ๋ฐฑ์ค€ 1774:์šฐ์ฃผ์‹ ๊ณผ์˜ ๊ต๊ฐ

๊ธ๊ธยท2025๋…„ 10์›” 2์ผ

์•Œ๊ณ ๋ฆฌ์ฆ˜

๋ชฉ๋ก ๋ณด๊ธฐ
19/31

๐Ÿš€๋ฌธ์ œ

1774๋ฒˆ: ์šฐ์ฃผ์‹ ๊ณผ์˜ ๊ต๊ฐ
LV : ๊ณจ๋“œ 3

๐Ÿš€ํ’€์ด ๊ณผ์ •

ํ•ด๋‹น ๋ฌธ์ œ๋Š” ์ตœ์†Œ์‹ ์žฅํŠธ๋ฆฌ(MST)๋ฅผ ๋งŒ๋“ค์–ด์•ผ ํ•œ๋‹ค.
MST๋ฅผ ๋งŒ๋“œ๋Š” ์•Œ๊ณ ๋ฆฌ์ฆ˜์€ ํฌ๋ฃจ์Šค์นผ๊ณผ ํ”„๋ฆผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์ด ์žˆ๋Š”๋ฐ, ์—ฌ๊ธฐ์—์„œ๋Š” ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์จ๋ณด๊ธฐ๋กœ ํ–ˆ๋‹ค.

์ด ๋ฌธ์ œ๊ฐ€ ์ผ๋ฐ˜์ ์ธ ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜๊ณผ ๋‹ค๋ฅธ ์ ์€ ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ ๊ฐ„์„  ์ •๋ณด๊ฐ€ ์žˆ๋‹ค๋Š” ์ ์ด๋‹ค.

์ฝ”๋“œ ํ๋ฆ„

โญ์ดˆ๊ธฐ ์„ค์ •

1) Node ํด๋ž˜์Šค ์ƒ์„ฑ

์œ„์น˜๊ฐ€ x, y ์ขŒํ‘œ๋กœ ๋‚˜์˜ค๊ธฐ ๋•Œ๋ฌธ์— Node ํด๋ž˜์Šค๋ฅผ ์ƒ์„ฑํ•ด์ค€๋‹ค.

class Node {
	long x, y;

	public Node(long x, long y) {
		this.x = x;
		this.y = y;
	}
}

2) Edge ํด๋ž˜์Šค ์ƒ์„ฑ

ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜์„ ์œ„ํ•ด์„œ๋Š” ๊ฐ€์ค‘์น˜๊ฐ€ ์ ์€ ๊ฐ„์„ ๋ถ€ํ„ฐ ์„ ํƒํ•ด์•ผ ํ•˜๊ธฐ ๋•Œ๋ฌธ์— Comparable์„ ์ ์šฉํ•ด์ค€๋‹ค.

class Edge implements Comparable<Edge> {
	int from, to;
	double w;

	public Edge(int from, int to, double w) {
		this.from = from;
		this.to = to;
		this.w = w;
	}

	@Override
	public int compareTo(Edge o) {
		// double ๋น„๊ต ์‹œ ์˜ค์ฐจ ๋ฌธ์ œ ๋•Œ๋ฌธ์— Math.signum()์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „
		return Double.compare(this.w, o.w);
	}
}

โญํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜

1) ์ดˆ๊ธฐ ์„ค์ •


// 1. ์ดˆ๊ธฐ ์„ค์ •
  parent = new int[N + 1];
  // ๋ถ€๋ชจ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
  for (int i = 1; i < N + 1; i++) {
  	parent[i] = i;
  }

2) ์ขŒํ‘œ๊ฐ’ ์ €์žฅ

// 2. ์ขŒํ‘œ๊ฐ’ ์ €์žฅ
List<Node> spots = new ArrayList<>(N + 1);
spots.add(null);// 0๋ฒˆ์งธ๋Š” ๋น„์–ด๋‘๊ธฐ

for (int i = 0; i < N; i++) {
  st = new StringTokenizer(br.readLine());
  long x = Long.parseLong(st.nextToken());
  long y = Long.parseLong(st.nextToken());

  spots.add(new Node(x, y));
}

3) ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ M๊ฐœ์˜ ํ†ต๋กœ ์ฒ˜๋ฆฌ

union-find๋กœ ์ง‘ํ•ฉ์„ ๋ฌถ์–ด์ค€๋‹ค.

int edgesCount = 0; // ์„ ํƒ๋œ ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜
for (int i = 0; i < M; i++) {
	st = new StringTokenizer(br.readLine());
	int from = Integer.parseInt(st.nextToken());
	int to = Integer.parseInt(st.nextToken());

	if (union(from, to)) {
		edgesCount++;
	}
}

4) ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฐ„์„  ์ •๋ณด ์ƒ์„ฑ

// 4. ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฐ„์„  ์ •๋ณด ์ƒ์„ฑ
List<Edge> edges = new ArrayList<>();
// ๊ฐ„์„ ์ •๋ณด ์ €์žฅ
for (int i = 1; i <= N; i++) {
	for (int j = i + 1; j <= N; j++) {
		double weight = getDistance(spots.get(i), spots.get(j));

		// Edge ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
		edges.add(new Edge(i, j, weight));
	}
}

5) ๊ฐ„์„ ์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ

// 5. ๊ฐ„์„ ์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ
Collections.sort(edges);

6) ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‹คํ–‰

double minTotalWeight = 0; // ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•  ํ†ต๋กœ์˜ ์ตœ์†Œ ๊ธธ์ด ํ•ฉ
int edgesCount = 0; // ์„ ํƒ๋œ ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜

for (Edge edge : edges) {
	// ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด
	if (union(edge.from, edge.to)) {
		minTotalWeight += edge.w;
		edgesCount++;
	}

	if (edgesCount == N - 1)
		break;
}

7) ๊ฒฐ๊ณผ ์ถœ๋ ฅ

System.out.printf("%.2f\n",minTotalWeight);

โญ๋ฉ”์„œ๋“œ ์ƒ์„ฑ

1) getDistance()

// ๊ฑฐ๋ฆฌ๋ฅด ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ œ๊ณฑ์„ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
private static double getDistance(Node n1, Node n2) {
  double dx = n1.x - n2.x;
  double dy = n1.y - n2.y;
  return Math.sqrt(dx * dx + dy * dy);
}

2) find()

private static int find(int a) {
if (parent[a] == a)
	return a;
return parent[a] = find(parent[a]);
}

3) union()

private static boolean union(int a, int b) {
int rootA = find(a);
int rootB = find(b);

// ์ด๋ฏธ ๊ฐ™์€ ์ง‘ํ•ฉ์ด๋ฉด ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹ค.
if (rootA == rootB)
	return false;

// ์ž‘์€ ๋ฒˆํ˜ธ์˜ ๋ฃจํŠธ๋ฅผ ๋ถ€๋ชจ๋กœ ์‹คํ–‰
if (rootA < rootB) {
	parent[rootB] = rootA;
} else {
	parent[rootA] = rootB;

}
return true;
}

๐Ÿš€์ „์ฒด์ฝ”๋“œ

import java.io.BufferedReader;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.StringTokenizer;

//๋…ธ๋“œ์˜ ์ขŒํ‘œ๋ฅผ ๋‚˜ํƒ€๋‚ด๋Š” ํด๋ž˜์Šค
class Node {
	long x, y;

	public Node(long x, long y) {
		this.x = x;
		this.y = y;
	}
}

//MST ์ƒ์„ฑํ•ด์•ผ ํ•œ๋‹ค.
//์„œ๋กœ์†Œ ์ง‘ํ•ฉ or prim ์•Œ๊ณ ๋ฆฌ์ฆ˜
class Edge implements Comparable<Edge> {
	int from, to;
	double w;

	public Edge(int from, int to, double w) {
		this.from = from;
		this.to = to;
		this.w = w;
	}

	@Override
	public int compareTo(Edge o) {
		// double ๋น„๊ต ์‹œ ์˜ค์ฐจ ๋ฌธ์ œ ๋•Œ๋ฌธ์— Math.signum()์„ ์‚ฌ์šฉํ•˜๋Š” ๊ฒƒ์ด ์•ˆ์ „
		return Double.compare(this.w, o.w);
	}
}

public class backjoon_1774_๊ต๊ฐ {
	static int[] parent;

	public static void main(String[] args) throws IOException {
		System.setIn(new FileInputStream("src/input.txt"));

		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

		StringTokenizer st = new StringTokenizer(br.readLine());

		int N = Integer.parseInt(st.nextToken());
	int M = Integer.parseInt(st.nextToken());

// 1. ์ดˆ๊ธฐ ์„ค์ •
parent = new int[N + 1];
// ๋ถ€๋ชจ ๋ฐฐ์—ด ์ดˆ๊ธฐํ™”
for (int i = 1; i < N + 1; i++) {
parent[i] = i;
}

// 2. ์ขŒํ‘œ๊ฐ’ ์ €์žฅ
List<Node> spots = new ArrayList<>(N + 1);
spots.add(null);// 0๋ฒˆ์งธ๋Š” ๋น„์–ด๋‘๊ธฐ
for (int i = 0; i < N; i++) {
	st = new StringTokenizer(br.readLine());
	long x = Long.parseLong(st.nextToken());
	long y = Long.parseLong(st.nextToken());

	spots.add(new Node(x, y));
}

// 3. ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ M๊ฐœ์˜ ํ†ต๋กœ ์ฒ˜๋ฆฌ (Union-Find๋กœ ๋ฏธ๋ฆฌ ์ง‘ํ•ฉ์œผ๋กœ ๋ฌถ๊ธฐ)
// ์ด๋ฏธ ์—ฐ๊ฒฐ๋œ ๊ฐ„์„ ์€ ๋ถ€๋ชจ๋ฅผ ๊ฐ™๊ฒŒ ํ•˜๊ธฐ
int edgesCount = 0; // ์„ ํƒ๋œ ๊ฐ„์„ ์˜ ๊ฐœ์ˆ˜
for (int i = 0; i < M; i++) {
	st = new StringTokenizer(br.readLine());
	int from = Integer.parseInt(st.nextToken());
	int to = Integer.parseInt(st.nextToken());

	if (union(from, to)) {
		edgesCount++;
	}
}

// 4. ๋ชจ๋“  ๊ฐ€๋Šฅํ•œ ๊ฐ„์„  ์ •๋ณด ์ƒ์„ฑ
List<Edge> edges = new ArrayList<>();
// ๊ฐ„์„ ์ •๋ณด ์ €์žฅ
for (int i = 1; i <= N; i++) {
	for (int j = i + 1; j <= N; j++) {
		double weight = getDistance(spots.get(i), spots.get(j));

		// Edge ๊ฐ์ฒด๋ฅผ ์ƒ์„ฑํ•˜์—ฌ ๋ฆฌ์ŠคํŠธ์— ์ถ”๊ฐ€
		edges.add(new Edge(i, j, weight));
	}
}

// 5. ๊ฐ„์„ ์„ ์˜ค๋ฆ„์ฐจ์ˆœ์œผ๋กœ ์ •๋ ฌ
Collections.sort(edges);

// 6. ํฌ๋ฃจ์Šค์นผ ์•Œ๊ณ ๋ฆฌ์ฆ˜ ์‹คํ–‰

double minTotalWeight = 0; // ์ƒˆ๋กœ ๋งŒ๋“ค์–ด์•ผ ํ•  ํ†ต๋กœ์˜ ์ตœ์†Œ ๊ธธ์ด ํ•ฉ


for (Edge edge : edges) {
	// ์‚ฌ์ดํด์ด ๋ฐœ์ƒํ•˜์ง€ ์•Š์œผ๋ฉด
	if (union(edge.from, edge.to)) {
		minTotalWeight += edge.w;
		edgesCount++;
	}

	if (edgesCount == N - 1)
		break;
}

// 7. ๊ฒฐ๊ณผ ์ถœ๋ ฅ
System.out.printf("%.2f\n",minTotalWeight);

}

// ๊ฑฐ๋ฆฌ๋ฅด ๊ตฌํ•˜๊ธฐ ์œ„ํ•ด์„œ ์ œ๊ณฑ์„ ํ™œ์šฉํ•ด์•ผ ํ•œ๋‹ค.
private static double getDistance(Node n1, Node n2) {
double dx = n1.x - n2.x;
double dy = n1.y - n2.y;
return Math.sqrt(dx * dx + dy * dy);
}

private static boolean union(int a, int b) {
int rootA = find(a);
int rootB = find(b);

// ์ด๋ฏธ ๊ฐ™์€ ์ง‘ํ•ฉ์ด๋ฉด ํ•ฉ์น˜์ง€ ์•Š๋Š”๋‹ค.
if (rootA == rootB)
	return false;

// ์ž‘์€ ๋ฒˆํ˜ธ์˜ ๋ฃจํŠธ๋ฅผ ๋ถ€๋ชจ๋กœ ์‹คํ–‰
if (rootA < rootB) {
	parent[rootB] = rootA;
} else {
	parent[rootA] = rootB;

}
return true;
}

private static int find(int a) {
if (parent[a] == a)
	return a;
return parent[a] = find(parent[a]);
}
}

0๊ฐœ์˜ ๋Œ“๊ธ€