본문 바로가기

Dot Algo∙ DS/PS

[프로그래머스] 위클리 챌린지 9주차 전력망 둘로 나누기 (Java)

    #9주차 전력망 둘로 나누기

    유형 : 그래프 탐색 DFS 또는 Union-Find

     

    코딩테스트 연습 - 9주차

    9 [[1,3],[2,3],[3,4],[4,5],[4,6],[4,7],[7,8],[7,9]] 3 7 [[1,2],[2,7],[3,7],[3,4],[4,5],[6,7]] 1

    programmers.co.kr

    ▸ 문제

    n개의 송전탑이 전선을 통해 하나의 트리 형태로 연결되어 있습니다. 당신은 이 전선들 중 하나를 끊어서 현재의 전력망 네트워크를 2개로 분할하려고 합니다. 이때, 두 전력망이 갖게 되는 송전탑의 개수를 최대한 비슷하게 맞추고자 합니다.

    송전탑의 개수 n, 그리고 전선 정보 wires가 매개변수로 주어집니다. 전선들 중 하나를 끊어서 송전탑 개수가 가능한 비슷하도록 두 전력망으로 나누었을 때, 두 전력망이 가지고 있는 송전탑 개수의 차이(절대값)를 return 하도록 solution 함수를 완성해주세요.

     제한사항

    • n은 2 이상 100 이하인 자연수입니다.
    • wires는 길이가 n-1인 정수형 2차원 배열입니다.
      • wires의 각 원소는 [v1, v2] 2개의 자연수로 이루어져 있으며, 이는 전력망의 v1번 송전탑과 v2번 송전탑이 전선으로 연결되어 있다는 것을 의미합니다.
      • 1 ≤ v1 < v2 ≤ n 입니다.
      • 전력망 네트워크가 하나의 트리 형태가 아닌 경우는 입력으로 주어지지 않습니다

     

    문제 풀이  

    주어진 노드의 최대 수는 총 100개이다. 각 노드의 모든 조합 경우의 수로 노드를 가르기에는 수가 너무 많다. 그래서 그냥 주어진 간선을 하나씩 끊어보는 브루트포스 탐색 방식을 사용하여 풀이를 하였다. 하나의 트리로 구성되어 있는 최대 99개의 간선을 가진 데이터를 각 1개씩 모두 끊어보면서 DFS탐색을 통해 노드의 갯수를 구하였다. 

     

    DFS 탐색 풀이

    1. 양방향 간선을 저장하는 인접리스트 자료구조를 초기화한다. list[i] = new ArrayList<>();
    2. n-1번 반복을 돌리면서 간선을 하나씩 뺀 두 개의 트리를 만든다. if(idx==i) continue;
    3. 인접리스트 자료구조로 노드의 데이터를 저장한다. list[a].add(b);
    4. DFS탐색으로 노드의 갯수를 탐색해준다. dfs(1,-1) > numOfNodes 
    5. 두 트리의 개수 차이를 n - (n-numOfNodes) 구하고 최솟값을 갱신한다.

     

    문제를 해결하고 나니 DFS 탐색으로 구하면 일단 인접리스트 배열을 계속해서 갱신하고 DFS탐색을 한다는 것이 로직 자체가 무거웠다. 그래서 서로소 집합 자료구조인 Union-Find를 사용하여 2차 풀이를 해봤다.

     

    Union-Find 풀이

    1. 각 노드의 부모노드를 저장하는 parents[]을 초기화한다.
    2. n-1번 반복을 돌리면서 간선을 하나씩 뺀 두 개의 트리를 만든다. if(idx==i) continue;
    3. 번호가 작은 노드가 부모노드로 가게끔 union(a,b)연산을 수행한다.
    4. 1번 노드와 연결되어있는 노드의 갯수를 구한다. tmp++;
    5. 두 트리의 개수 차이를 n - (n-tmp) 구하고 최솟값을 갱신한다.

     

    Union-find 자료구조를 통해 간선 중심이 아닌 노드 중심으로 탐색을 하니 DFS탐색보다 더 빠른 수행을 보이는 것을 확인할 수 있었다.

     

    풀이 코드 

    DFS 풀이

    import java.util.ArrayList;
    import java.util.List;
    
    class Solution {
        static List<Integer>[] list;
    	static int numOfNodes;
        public int solution(int n, int[][] wires) {
            int answer = 100;
            int idx=0;
            list = new ArrayList[n+1];
            
            while(idx<n-1) {
    	        for(int i=1; i<n+1; i++) {
    	        	list[i] = new ArrayList<>();
    	        }
    	        
    	        for(int i=0; i<wires.length; i++) {
    	        	if(idx == i) continue;
    	        	int a = wires[i][0];
    	        	int b = wires[i][1];
    	        	
    	        	list[a].add(b);
    	        	list[b].add(a);
    	        }
    	        
    	        numOfNodes=0;
    	        dfs(1, -1);
    	        int res = Math.abs(n - 2*numOfNodes);
    	        answer = Math.min(res, answer);
    	        idx++;
            }
            return answer;
        }
        
        static void dfs(int idx, int pa) {
    		numOfNodes++;
    		for(int nxt : list[idx]) {
    			if(pa != nxt) {
    				dfs(nxt, idx);
    			}
    		}
    	}
    	
    }

     

    Union-Find 풀이

    class Solution {
        static int[] parents;
        public int solution(int n, int[][] wires) {
            int answer = 100;
            int idx =0;
            parents = new int[n+1];
            while(idx < n-1) {
                for(int i=1; i<n+1; i++) {
                    parents[i] =i;
                }
    
                for(int i=0; i<wires.length; i++) {
                    if(idx == i) continue;
    
                    int a = wires[i][0];
                    int b = wires[i][1];
    
                    union(a,b);
                }
    
    
                int tmp =0;
                for(int i=1; i<n+1; i++) {
                    if(find(parents[i]) == 1) tmp++;
                }
                int res = Math.abs(n-2*tmp);
    
                answer = Math.min(res, answer);
                idx++;
            }
    
            return answer;
        }
    
        static int find(int x) {
            if(parents[x] ==x) return x;
            return find(parents[x]);
        }
    
        static void union(int x, int y) {
            int rx = find(x);
            int ry = find(y);
            if(ry < rx) {
                int tmp = rx;
                rx = ry;
                ry = tmp;
            }
    
            if(rx!=ry) {
                parents[ry]= rx;
            }
        }
    }

     

     

    결과 비교