본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 19542번 전단지 돌리기 (Java)

    #19542 전단지 돌리기

    난이도 : 골드 4

    유형 : 트리 / DFS 

     

    19542번: 전단지 돌리기

    현민이는 트리 모양의 길 위에서 오토바이를 타고 전단지를 돌리려고 한다. 현민이의 목표는 케니소프트에서 출발하여 모든 노드에 전단지를 돌리고, 다시 케니소프트로 돌아오는 것이다. 현민

    www.acmicpc.net

    ▸ 문제

    현민이는 트리 모양의 길 위에서 오토바이를 타고 전단지를 돌리려고 한다. 현민이의 목표는 케니소프트에서 출발하여 모든 노드에 전단지를 돌리고, 다시 케니소프트로 돌아오는 것이다. 현민이는 힘이 좋기 때문에 현재 노드에서 거리가 D이하인 모든 노드에 전단지를 돌릴 수 있다.

    날씨가 매우 덥기 때문에, 현민이는 최소한만 이동해서 목표를 달성하고 싶다! 현민이를 위해 현민이가 이동해야 하는 총 거리를 구해주자.

     입력

    첫번째 줄에는 노드의 개수 N(1≤N≤100)과 케니소프트의 위치 S(1≤S≤N), 힘 D(0≤D≤N)이 주어진다.

    두 번째 줄부터 N번째 줄까지, 트리의 간선 정보를 의미하는 두 자연수 x, y가 공백으로 구분되어 주어진다. 이는 x번 노드와 y번 노드가 연결되어 있음을 의미한다. (1≤x,y≤N, x≠y)

    주어지는 연결관계는 트리를 구성하며, 모든 간선의 길이는 1이다.

     출력

    현민이가 목표를 완수하기 위해 이동해야 하는 최소 거리를 출력하여라.

     

    문제 풀이  

    처음에 문제 이해가 잘안됐는데 알고보니 거리가 D 이하인 노드까지 움직일 수 있는 것이 아니라 D거리 이하에 있는 노드는 방문하지 않고전단지를 배포할 수 있다는 뜻이었다. 이는 트리 DFS 탐색으로 구할 수 있다. D의 거리는 리프노드부터의 거리를 세어준다. D보다 값이 커지는 일정 노드부터 현민이가 이동해야 하는 노드이다. 

     

    D가 1인 트리가 다음과 같이 주어졌을 때 파란색을 칠한 노드만 탐색해주면 된다. 트리의 최단 거리는 교차 간선이 없기 때문에 간선의 수*2를 해주면 된다. 

     

    D가 1일 경우

     

    설계

    1. 입력 데이터를 인접리스트 배열에 저장한다. (x, y가 항상 부모-자식 관계의 순서로 주어지는 것이 아니기 떄문에 양방향으로 입력받아야 한다.)
    2. s를 시작점으로 dfs 트리를 탐색한다. dfs(s, -1);
      1. 리프노드를 시작으로 depth를 1씩 증가시킨다. 서브노드가 2개 이상일 경우 더 깊은 depth값을 적용한다. 
      2. depth >= d, cnt++; 노드의 거리가 d가 넘는 경우 탐색해야 하는 노드이므로 카운트해준다. 
        1. 시작점은 카운트하지 않아도 된다.
    3. 왕복 간선의 갯수 = 시작점을 제외한 방문노드의 갯수*2를 출력해준다. cnt*2

     

    풀이 코드 

    import java.io.*;
    import java.util.*;
    
    public class Main {
    
    	static int n,s,d,cnt;
    	static List<Integer>[] list;
    	static int[] depth;
    	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());
    		s = Integer.parseInt(st.nextToken());
    		d = Integer.parseInt(st.nextToken());
    		
    		depth = new int[n+1];
    		list = new ArrayList[n+1];
    		for(int i=1; i<n+1; i++) {
    			list[i] = new ArrayList<>();
    		}
    		
    		for(int i=0; i<n-1; i++) {
    			st = new StringTokenizer(br.readLine());
    			int a = Integer.parseInt(st.nextToken());
    			int b = Integer.parseInt(st.nextToken());
    			list[a].add(b);
    			list[b].add(a);
    		}
    		
    		dfs(s, -1);
    		System.out.println(cnt*2);
    	}
    	
    	static int dfs(int idx, int pa) {
    		for(int nxt : list[idx]) {
    			if(nxt != pa) {
    				depth[idx] = Math.max(depth[idx], dfs(nxt, idx)+1);
    			}
    		}
    		
    		if(idx!=s && depth[idx] >=  d) {
    			cnt++;
    		}
    		return depth[idx];
    	}
    }