STUDY πŸ’›/μ•Œκ³ λ¦¬μ¦˜

[BOJ] 2887 ν–‰μ„± 터널 JAVA

DONI. 2021. 2. 9. 13:43
λ°˜μ‘ν˜•

 

[문제]
https://www.acmicpc.net/problem/2887

 

2887번: ν–‰μ„± 터널

첫째 쀄에 ν–‰μ„±μ˜ 개수 N이 주어진닀. (1 ≤ N ≤ 100,000) λ‹€μŒ N개 μ€„μ—λŠ” 각 ν–‰μ„±μ˜ x, y, zμ’Œν‘œκ°€ 주어진닀. μ’Œν‘œλŠ” -109보닀 ν¬κ±°λ‚˜ κ°™κ³ , 109보닀 μž‘κ±°λ‚˜ 같은 μ •μˆ˜μ΄λ‹€. ν•œ μœ„μΉ˜μ— 행성이 두 개 이

www.acmicpc.net


λ•ŒλŠ” 2040λ…„, μ΄λ―Όν˜μ€ μš°μ£Όμ— μžμ‹ λ§Œμ˜ 왕ꡭ을 λ§Œλ“€μ—ˆλ‹€. 왕ꡭ은 N개의 ν–‰μ„±μœΌλ‘œ 이루어져 μžˆλ‹€. λ―Όν˜μ΄λŠ” 이 행성을 효율적으둜 μ§€λ°°ν•˜κΈ° μœ„ν•΄μ„œ 행성을 μ—°κ²°ν•˜λŠ” 터널을 λ§Œλ“€λ €κ³  ν•œλ‹€.

행성은 3차원 μ’Œν‘œμœ„μ˜ ν•œ 점으둜 μƒκ°ν•˜λ©΄ λœλ‹€. 두 ν–‰μ„± A(xA, yA, zA)와 B(xB, yB, zB)λ₯Ό ν„°λ„λ‘œ μ—°κ²°ν•  λ•Œ λ“œλŠ” λΉ„μš©μ€ min(|xA-xB|, |yA-yB|, |zA-zB|)이닀.

λ―Όν˜μ΄λŠ” 터널을 총 N-1개 κ±΄μ„€ν•΄μ„œ λͺ¨λ“  행성이 μ„œλ‘œ μ—°κ²°λ˜κ²Œ ν•˜λ €κ³  ν•œλ‹€. μ΄λ•Œ, λͺ¨λ“  행성을 ν„°λ„λ‘œ μ—°κ²°ν•˜λŠ”λ° ν•„μš”ν•œ μ΅œμ†Œ λΉ„μš©μ„ κ΅¬ν•˜λŠ” ν”„λ‘œκ·Έλž¨μ„ μž‘μ„±ν•˜μ‹œμ˜€.



[μž…λ ₯]
첫째 쀄에 ν–‰μ„±μ˜ 개수 N이 주어진닀. (1 ≤ N ≤ 100,000) λ‹€μŒ N개 μ€„μ—λŠ” 각 ν–‰μ„±μ˜ x, y, zμ’Œν‘œκ°€ 주어진닀. μ’Œν‘œλŠ” -109보닀 ν¬κ±°λ‚˜ κ°™κ³ , 109보닀 μž‘κ±°λ‚˜ 같은 μ •μˆ˜μ΄λ‹€. ν•œ μœ„μΉ˜μ— 행성이 두 개 이상 μžˆλŠ” κ²½μš°λŠ” μ—†λ‹€.



[좜λ ₯]
첫째 쀄에 λͺ¨λ“  행성을 ν„°λ„λ‘œ μ—°κ²°ν•˜λŠ”λ° ν•„μš”ν•œ μ΅œμ†Œ λΉ„μš©μ„ 좜λ ₯ν•œλ‹€.

 




[Solution 1]
- μ΅œμ†Œμ‹ μž₯트리 문제
- 크루슀칼 μ•Œκ³ λ¦¬μ¦˜ μ‚¬μš©
- κ°„μ„  μ΅œμ†Œκ°’μ„ κ΅¬ν•˜λŠ” κ³Όμ •(line 57~70)μ—μ„œ λ©”λͺ¨λ¦¬ or μ‹œκ°„μ΄ˆκ³Ό

package boj2887_행성터널;

/* μ΅œμ†Œμ‹ μž₯트리 문제
 * 크루슀칼 μ•Œκ³ λ¦¬μ¦˜
 * -> λ©”λͺ¨λ¦¬μ΄ˆκ³Ό
 * weight의 minκ°’ κ΅¬ν•˜λŠ” λΆ€λΆ„μ—μ„œ 100,000*99999/2*12(byte) > 128MB
 * */

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main {
	static class Edge implements Comparable<Edge>{
		int start, end, weight;
		
		public Edge(int start, int end, int weight) {
			this.start = start;
			this.end = end;
			this.weight = weight;
		}

		@Override
		public int compareTo(Edge o) {
			return weight-o.weight;
		}
	}
	
	static int n;
	static int[][] space;
	static PriorityQueue<Edge> pq = new PriorityQueue<>();
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		space = new int[n][3];
		int [] parent = new int[n];
		
		int answer = 0;
		int weight = 0;
		
		//iν–‰μ„±μ˜ μ’Œν‘œκ°’ input
		for(int i=0; i<n; ++i) {
			st = new StringTokenizer(br.readLine());
			
			space[i][0] = Integer.parseInt(st.nextToken());		//x
			space[i][1] = Integer.parseInt(st.nextToken());		//y
			space[i][2] = Integer.parseInt(st.nextToken());		//z
		}
		
		//Aν–‰μ„±-Bν–‰μ„± μ—°κ²°μ‹œ λΉ„μš© : min(|xA-xB|, |yA-yB|, |zA-zB|)
		//i-j = j-i μ΄λ―€λ‘œ jλŠ” iλΆ€ν„° μ‹œμž‘(λ‘λ²ˆ ν•  ν•„μš”x)
		for(int i=0; i<n; ++i) {
			for(int j=i; j<n; ++j) {
				if(i == j) continue;
				
				//x
				weight = Math.abs(space[i][0]-space[j][0]);
				//x, y
				weight = Math.min(weight, Math.abs(space[i][1]-space[j][1]));
				//x, y, z
				weight = Math.min(weight, Math.abs(space[i][2]-space[j][2]));

				pq.add(new Edge(i, j, weight));
			}
		}
		
		//parentλ₯Ό μžμ‹ μœΌλ‘œ μ΄ˆκΈ°ν™”
		for(int i=0; i<n; ++i) {
			parent[i] = i;
		}
		
		//κ°€μ€‘μΉ˜ μž‘μ€κ²ƒ(μ•žμͺ½idx)λΆ€ν„° μ„ νƒν•˜λ©΄μ„œ 크루슀칼 μ•Œκ³ λ¦¬μ¦˜ μ‹€ν–‰
		int len = pq.size();
		for(int i=0; i<len; ++i) {
			Edge node = pq.poll();
			
			//사이클이 λ°œμƒν•˜μ§€ μ•ŠλŠ” 경우(μ‹œμž‘λ…Έλ“œμ™€ λ„μ°©λ…Έλ“œμ˜ λ£¨νŠΈλ…Έλ“œκ°€ κ°™μ§€μ•ŠμœΌλ©΄)
			//에 집합에 포함(union ν•¨μˆ˜ μ‹€ν–‰), λ…Έλ“œ(터널) μ—°κ²°
			if(ckCycle(parent, node.start) != ckCycle(parent, node.end)) {
				union(parent, node.start, node.end);
				answer += node.weight;
			}
		}
		
		System.out.println(answer);
	}
	
	//xκ°€ μ†ν•œ 집합 μ°ΎκΈ°(사이클 λ°œμƒ 확인), λ£¨νŠΈλ…Έλ“œ λ°˜ν™˜
	static int ckCycle(int[] parent, int node) {
		//parent[node]κ°€ ν˜„μž¬ λ…Έλ“œλž‘ λ‹€λ₯΄λ©΄ λ£¨νŠΈλ…Έλ“œκ°€ λ”°λ‘œ μžˆμœΌλ―€λ‘œ
		//λ£¨νŠΈλ…Έλ“œ μ°Ύμ•„μ„œ μ˜¬λΌκ°€λŠ” μž¬κ·€
		if(parent[node] != node) {
			parent[node] = ckCycle(parent, parent[node]);
		}
		return parent[node];
	}
	
	//start, end μ†ν•œ 집합 ν•©μΉ˜κΈ°
	static void union(int[] parent, int start, int end) {
		//start와 endλ…Έλ“œμ˜ λ£¨νŠΈλ…Έλ“œ μ°Ύμ•„μ„œ μ €μž₯
		start = ckCycle(parent, start);
		end = ckCycle(parent, end);
		
		//더 μœ„μ— μžˆλŠ”(μˆ«μžκ°€ μž‘μ€) λ…Έλ“œκ°€ λ£¨νŠΈλ…Έλ“œκ°€ 됨
		if(start < end) parent[end] = start;
		else parent[start] = end;
	}
}

 

[Solution 2]
- 크루슀칼 μ•Œκ³ λ¦¬μ¦˜ κ·ΈλŒ€λ‘œ μ‚¬μš©
- min값을 κ΅¬ν•˜μ§€ μ•Šκ³  μš°μ„ μˆœμœ„ 큐λ₯Ό 이용
- x, y, z κ°„μ„ μ˜ κ°€μ€‘μΉ˜λ₯Ό 각자 κ΅¬ν•œ ν›„
- κ°€μ€‘μΉ˜κ°€ μž‘μ€ 순으둜 μ •λ ¬ ν›„ λ…Έλ“œλ₯Ό μ—°κ²°ν•˜λ©΄ μ‹œκ°„, λ©”λͺ¨λ¦¬ μ ˆμ•½!

package boj2887_행성터널;

import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.PriorityQueue;
import java.util.StringTokenizer;

public class Main2 {
	static class Edge implements Comparable<Edge>{
		int start, end, weight;
		
		public Edge(int start, int end, int weight) {
			this.start = start;
			this.end = end;
			this.weight = weight;
		}
		
		//κ°€μ€‘μΉ˜ μ˜€λ¦„μ°¨μˆœ μ •λ ¬
		@Override
		public int compareTo(Edge o) {
			return weight-o.weight;
		}
	}
	
	static class Node implements Comparable<Node> {
		int pos, num;		//μ’Œν‘œ, λ…Έλ“œλ²ˆν˜Έ
		
		public Node(int pos, int num) {
			this.pos = pos;
			this.num = num;
		}
		
		//μ’Œν‘œ μ˜€λ¦„μ°¨μˆœ, μ’Œν‘œκ°€ κ°™μœΌλ©΄ λ…Έλ“œμˆœ
		@Override
		public int compareTo(Node o) {
			if(pos == o.pos) return num - o.num;
			return pos - o.pos;
		}
	}
	
	static int n;
	static PriorityQueue<Edge> pq = new PriorityQueue<>();
	
	public static void main(String[] args) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		StringTokenizer st = new StringTokenizer(br.readLine());
		
		n = Integer.parseInt(st.nextToken());
		int [] parent = new int[n];
		
		//μš°μ„ μˆœμœ„ 큐λ₯Ό μ‚¬μš©ν•΄μ„œ μ •λ ¬ 해주지 μ•Šμ•„λ„λ¨
		PriorityQueue<Node> x = new PriorityQueue<>();
		PriorityQueue<Node> y = new PriorityQueue<>();
		PriorityQueue<Node> z = new PriorityQueue<>();
		
		int answer = 0;
		
		//iν–‰μ„±μ˜ μ’Œν‘œκ°’ input
		for(int i=0; i<n; ++i) {
			st = new StringTokenizer(br.readLine());
			
			x.add(new Node(Integer.parseInt(st.nextToken()), i));
			y.add(new Node(Integer.parseInt(st.nextToken()), i));
			z.add(new Node(Integer.parseInt(st.nextToken()), i));
		}	
		
		//Aν–‰μ„±-Bν–‰μ„± μ—°κ²°λΉ„μš© : x,y,zμ’Œν‘œ κ³„μ‚°κ°’μ˜ μ ˆλŒ€κ°’ 쀑 μ΅œμ†Ÿκ°’μ΄μ§€λ§Œ μ΅œμ†Ÿκ°’μ„ κ΅¬ν•˜λŠ” 과정은 ν•„μš”μ—†μŒ.
		//μ˜€λ¦„μ°¨μˆœ ν›„ λΉ„μš©μ΄ μž‘μ€ κ°„μ„ (터널)λΆ€ν„° μ—°κ²°ν•΄μ„œ μ΅œμ†Œκ°’μ„ κ³„μ‚°ν•˜λŠ” κ³Όμ • 없어도 γ„±γ…Š
		//|xA-xB|
		for(int i=0; i<n-1; ++i) {
			Node A = x.poll();
			Node B = x.peek();
			pq.add(new Edge(A.num, B.num, Math.abs(A.pos - B.pos)));
		}
		
		//|yA-yB|
		for(int i=0; i<n-1; ++i) {
			Node A = y.poll();
			Node B = y.peek();
			pq.add(new Edge(A.num, B.num, Math.abs(A.pos - B.pos)));
		}
		
		//|zA-zB|
		for(int i=0; i<n-1; ++i) {
			Node A = z.poll();
			Node B = z.peek();
			pq.add(new Edge(A.num, B.num, Math.abs(A.pos - B.pos)));
		}
		
		//parentλ₯Ό μžμ‹ μœΌλ‘œ μ΄ˆκΈ°ν™”
		for(int i=0; i<n; ++i) {
			parent[i] = i;
		}
		
		//κ°€μ€‘μΉ˜ μž‘μ€κ²ƒ(μ•žμͺ½idx)λΆ€ν„° μ„ νƒν•˜λ©΄μ„œ 크루슀칼 μ•Œκ³ λ¦¬μ¦˜ μ‹€ν–‰
		int len = pq.size();
		for(int i=0; i<len; ++i) {
			Edge node = pq.poll();
			
			//사이클이 λ°œμƒν•˜μ§€ μ•ŠλŠ” 경우(μ‹œμž‘λ…Έλ“œμ™€ λ„μ°©λ…Έλ“œμ˜ λ£¨νŠΈλ…Έλ“œκ°€ κ°™μ§€μ•ŠμœΌλ©΄)
			//에 집합에 포함(union ν•¨μˆ˜ μ‹€ν–‰), λ…Έλ“œ(터널) μ—°κ²°
			if(ckCycle(parent, node.start) != ckCycle(parent, node.end)) {
				union(parent, node.start, node.end);
				answer += node.weight;
			}
		}
		
		System.out.println(answer);
	}
	
	//xκ°€ μ†ν•œ 집합 μ°ΎκΈ°(사이클 λ°œμƒ 확인), λ£¨νŠΈλ…Έλ“œ λ°˜ν™˜
	static int ckCycle(int[] parent, int node) {
		//parent[node]κ°€ ν˜„μž¬ λ…Έλ“œλž‘ λ‹€λ₯΄λ©΄ λ£¨νŠΈλ…Έλ“œκ°€ λ”°λ‘œ μžˆμœΌλ―€λ‘œ
		//λ£¨νŠΈλ…Έλ“œ μ°Ύμ•„μ„œ μ˜¬λΌκ°€λŠ” μž¬κ·€
		if(parent[node] != node) {
			parent[node] = ckCycle(parent, parent[node]);
		}
		return parent[node];
	}
	
	//start, end μ†ν•œ 집합 ν•©μΉ˜κΈ°
	static void union(int[] parent, int start, int end) {
		//start와 endλ…Έλ“œμ˜ λ£¨νŠΈλ…Έλ“œ μ°Ύμ•„μ„œ μ €μž₯
		start = ckCycle(parent, start);
		end = ckCycle(parent, end);
		
		//더 μœ„μ— μžˆλŠ”(μˆ«μžκ°€ μž‘μ€) λ…Έλ“œκ°€ λ£¨νŠΈλ…Έλ“œκ°€ 됨
		if(start < end) parent[end] = start;
		else parent[start] = end;
	}
}

 

λ°˜μ‘ν˜•