본문 바로가기

코딩/프로그래머스

[프로그래머스/JAVA] 코딩테스트연습 > Summer/Winter Coding(~2018) > 배달 (by 다알쥐AI)

728x90
반응형

[배달] 코딩테스트 연습 > Summer/Winter Coding(~2018) > 배달

 

틱톡라이트 초대링크  https://lite.tiktok.com/t/ZSjqX7SfC/

 

[기간 한정] 보는 재미로, 버는 재미로! 영상만 봐도, 좋아요만 눌러도, 검색만 해도, 포인트가 차

 

www.tiktok.com

 

 

※ 주의 : 문제풀이 방법은 다양합니다. 참고만 해주세요

[문제설명]

더보기

N개의 마을로 이루어진 나라가 있습니다. 이 나라의 각 마을에는 1부터 N까지의 번호가 각각 하나씩 부여되어 있습니다. 각 마을은 양방향으로 통행할 수 있는 도로로 연결되어 있는데, 서로 다른 마을 간에 이동할 때는 이 도로를 지나야 합니다. 도로를 지날 때 걸리는 시간은 도로별로 다릅니다.

 

현재 1번 마을에 있는 음식점에서 각 마을로 음식 배달을 하려고 합니다. 각 마을로부터 음식 주문을 받으려고 하는데, N개의 마을 중에서 K 시간 이하로 배달이 가능한 마을에서만 주문을 받으려고 합니다. 다음은 N = 5, K = 3인 경우의 예시입니다.

위 그림에서 1번 마을에 있는 음식점은 [1, 2, 4, 5] 번 마을까지는 3 이하의 시간에 배달할 수 있습니다. 그러나 3번 마을까지는 3시간 이내로 배달할 수 있는 경로가 없으므로 3번 마을에서는 주문을 받지 않습니다. 따라서 1번 마을에 있는 음식점이 배달 주문을 받을 수 있는 마을은 4개가 됩니다.


마을의 개수 N, 각 마을을 연결하는 도로의 정보 road, 음식 배달이 가능한 시간 K가 매개변수로 주어질 때, 음식 주문을 받을 수 있는 마을의 개수를 return 하도록 solution 함수를 완성해주세요.

 

제한사항

  • 마을의 개수 N은 1 이상 50 이하의 자연수입니다.
  • road의 길이(도로 정보의 개수)는 1 이상 2,000 이하입니다.
  • road의 각 원소는 마을을 연결하고 있는 각 도로의 정보를 나타냅니다.
  • road는 길이가 3인 배열이며, 순서대로 (a, b, c)를 나타냅니다.
    • a, b(1 ≤ a, b ≤ N, a != b)는 도로가 연결하는 두 마을의 번호이며, c(1 ≤ c ≤ 10,000, c는 자연수)는 도로를 지나는데 걸리는 시간입니다.
    • 두 마을 a, b를 연결하는 도로는 여러 개가 있을 수 있습니다.
    • 한 도로의 정보가 여러 번 중복해서 주어지지 않습니다.
  • K는 음식 배달이 가능한 시간을 나타내며, 1 이상 500,000 이하입니다.
  • 임의의 두 마을간에 항상 이동 가능한 경로가 존재합니다.
  • 1번 마을에 있는 음식점이 K 이하의 시간에 배달이 가능한 마을의 개수를 return 하면 됩니다.

입출력 예


입출력 예 설명

입출력 예 #1
문제의 예시와 같습니다.

 

입출력 예 #2
주어진 마을과 도로의 모양은 아래 그림과 같습니다.


1번 마을에서 배달에 4시간 이하가 걸리는 마을은 [1, 2, 3, 5] 4개이므로 4를 return 합니다.


[간단설명]

도로 1에서 K시간 내에 배달 할 수 있는 도로 개수 구하기

 

[접근방법]

1. 거리, 방문체크 가능한 노드 클래스를 만든다.

2. 도로 개수만큼 노드 리스트를 미리 만든다.

3. 만들어진 노드리스트에 각 도로를 양방향으로 넣어준다.

4. 우선순위 큐를 만든다.

5. 정답 set을 만든다.(방문가능한 도로개수)

6. 도로 1번의 노드를 넣는다.

7. BFS 탐색 시작

    7.1. 현재 노드를 꺼낸다.

    7.2. 다음 노드를 탐색한다.

    7.3. K시간을 벗어나거나, 이미 방문했으면 PASS

    7.4. 정답 set에 현재 도로를 저장한다.

    7.5. 처음 방문이면, 새로운 거리를 계산해서 넣는다.

    7.6. 기존 방문이면, 기존 값과 현재 계산한 거리 중 최소거리를 다시 넣는다.

8. 정답 set.size 리턴 

 

 

[주의사항]

BFS 탐색시 일반 큐를 사용하게 되면, 거리 계산 갱신에 실패할 수가 있다.

ㄴ> 우선순위큐를 사용해서, 최소 거리 순서로 탐색해야 거리 계산 갱신이 정확하다.

 

[소스공개]

import java.util.*;
class Solution {
    // 노드 클래스 
    class Node implements Comparable<Node>{
        List<Node> edge;
        int num;
        int dist;
        boolean visited;
        Node(int num, int dist){
            edge = new LinkedList<>();
            this.num = num;
            this.dist = dist;
            this.visited = false;
        }
        // 노느 연결
        public void add(Node node){
            edge.add(node);
        }
        // 거리순 정렬 
        @Override
        public int compareTo(Node o1){
            return this.dist - o1.dist;
        }
    }
    public int solution(int N, int[][] road, int K) {
        // 마을개수만큼 노드 만들기(0은 버림)
        List<Node> list = new LinkedList<>();
        for(int i=0;i<=N;i++){
            list.add(new Node(i,0));
        }
        // 연결형 그래프를 만든다.
        for(int[] r : road){
            int a = r[0];
            int b = r[1];
            int c = r[2];
            list.get(a).add(new Node(b,c));
            list.get(b).add(new Node(a,c));    
        }
        // 거리계산용 우선순위큐 
        PriorityQueue<Node> que = new PriorityQueue<>();
        // 배달가능한 도로 저장 set
        Set<Integer> set = new HashSet<>();
        // 1번 도로를 큐에 넣는다.
        list.get(1).visited = true;
        que.offer(list.get(1));
        set.add(1);
        // BFS 탐색
        while(!que.isEmpty()){
            // 현재 노드를 꺼낸다 
            Node now = que.poll();
            // 다음 노드를 탐색 
            for(Node next : now.edge){
                // 배달가능한 시간 K를 초과하면 PASS
                if(now.dist+next.dist>K) continue;
                // 방문했으면 PASS
                if(next.visited) continue;
                // 방문 체크
                next.visited = true;
                // 정답 추가
                set.add(next.num);
                // 처음 꺼내온 값이 0이면 아직 지나지 않은 도로이다.
                if(list.get(next.num).dist==0){
                    // 처음 방문한 도로의 거리를 계산
                    list.get(next.num).dist = now.dist+next.dist;  
                // 이미 값이 있으면, 지난 적이 있는 도로이다.
                }else{
                    // 예전에 지난 값과, 현재 값 중에 더 작은 값 저장(최소거리)
                    list.get(next.num).dist = Math.min(list.get(next.num).dist,now.dist+next.dist); 
                }
                // 큐에 노드를 추가 
                que.offer(list.get(next.num));
            }
        }
        // 방문 가능한 도로 개수 리턴    
        return set.size();
    }
}

 

[실행결과]

 

 

 

 

반응형