ABOUT ME

-

Today
-
Yesterday
-
Total
-
  • [BOJ] 2887 ν–‰μ„± 터널 JAVA
    STUDY πŸ’›/μ•Œκ³ λ¦¬μ¦˜ 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;
    	}
    }

     

    λ°˜μ‘ν˜•
Designed by Tistory.