Devtraces
개발자취
Devtraces
전체 방문자
오늘
어제
  • 분류 전체보기
    • Baekjoon
    • Programmers

블로그 메뉴

  • 홈
  • 태그
  • 방명록

공지사항

인기 글

태그

  • Trie
  • level4
  • dfs
  • two pointer
  • map
  • math
  • sort
  • recursive
  • java
  • level2
  • programmers
  • Matrix
  • floyd-warshall
  • Set
  • Tree
  • union-find
  • greedy
  • PriorityQueue
  • 그리디 알고리즘
  • prime number
  • DP
  • Dijkstra
  • stack
  • level3
  • BFS
  • Kakao
  • GCD
  • Queue
  • binary search
  • 백준

최근 댓글

최근 글

티스토리

Devtraces
Programmers

[프로그래머스 Level.3] 합승 택시 요금 (2021 KAKAO BLIND RECRUITMENT) (Java)

[프로그래머스 Level.3] 합승 택시 요금 (2021 KAKAO BLIND RECRUITMENT) (Java)
Programmers

[프로그래머스 Level.3] 합승 택시 요금 (2021 KAKAO BLIND RECRUITMENT) (Java)

2023. 3. 29. 13:51

문제 링크

https://school.programmers.co.kr/learn/courses/30/lessons/72413

 

프로그래머스

코드 중심의 개발자 채용. 스택 기반의 포지션 매칭. 프로그래머스의 개발자 맞춤형 프로필을 등록하고, 나와 기술 궁합이 잘 맞는 기업들을 매칭 받으세요.

programmers.co.kr

 

 

 

 

 

코딩테스트 연습 > 2021 KAKAO BLIND RECRUITMENT > 합승 택시 요금

 

 

 

문제 설명

 

 

 

[본 문제는 정확성과 효율성 테스트 각각 점수가 있는 문제입니다.]

 

밤늦게 귀가할 때 안전을 위해 항상 택시를 이용하던 무지는 최근 야근이 잦아져 택시를 더 많이 이용하게 되어 택시비를 아낄 수 있는 방법을 고민하고 있습니다.

 

"무지"는 자신이 택시를 이용할 때 동료인 어피치 역시 자신과 비슷한 방향으로 가는 택시를 종종 이용하는 것을 알게 되었습니다.

 

"무지"는 "어피치"와 귀가 방향이 비슷하여 택시 합승을 적절히 이용하면 택시요금을 얼마나 아낄 수 있을 지 계산해 보고 "어피치"에게 합승을 제안해 보려고 합니다.

 

 

 

 

위 예시 그림은 택시가 이동 가능한 반경에 있는 6개 지점 사이의 이동 가능한 택시노선과 예상요금을 보여주고 있습니다.
그림에서 A와 B 두 사람은 출발지점인 4번 지점에서 출발해서 택시를 타고 귀가하려고 합니다. A의 집은 6번 지점에 있으며 B의 집은 2번 지점에 있고 두 사람이 모두 귀가하는 데 소요되는 예상 최저 택시요금이 얼마인 지 계산하려고 합니다.

 

 

  • 그림의 원은 지점을 나타내며 원 안의 숫자는 지점 번호를 나타냅니다.
    • 지점이 n개일 때, 지점 번호는 1부터 n까지 사용됩니다.
  • 지점 간에 택시가 이동할 수 있는 경로를 간선이라 하며, 간선에 표시된 숫자는 두 지점 사이의 예상 택시요금을 나타냅니다.
    • 간선은 편의 상 직선으로 표시되어 있습니다.
    • 위 그림 예시에서, 4번 지점에서 1번 지점으로(4→1) 가거나, 1번 지점에서 4번 지점으로(1→4) 갈 때 예상 택시요금은 10원으로 동일하며 이동 방향에 따라 달라지지 않습니다.
  • 예상되는 최저 택시요금은 다음과 같이 계산됩니다.
    • 4→1→5 : A, B가 합승하여 택시를 이용합니다. 예상 택시요금은 10 + 24 = 34원 입니다.
    • 5→6 : A가 혼자 택시를 이용합니다. 예상 택시요금은 2원 입니다.
    • 5→3→2 : B가 혼자 택시를 이용합니다. 예상 택시요금은 24 + 22 = 46원 입니다.
    • A, B 모두 귀가 완료까지 예상되는 최저 택시요금은 34 + 2 + 46 = 82원 입니다.

 


 

[문제]

지점의 개수 n, 출발지점을 나타내는 s, A의 도착지점을 나타내는 a, B의 도착지점을 나타내는 b, 지점 사이의 예상 택시요금을 나타내는 fares가 매개변수로 주어집니다. 이때, A, B 두 사람이 s에서 출발해서 각각의 도착 지점까지 택시를 타고 간다고 가정할 때, 최저 예상 택시요금을 계산해서 return 하도록 solution 함수를 완성해 주세요.
만약, 아예 합승을 하지 않고 각자 이동하는 경우의 예상 택시요금이 더 낮다면, 합승을 하지 않아도 됩니다.

 

 

[제한사항]

  • 지점갯수 n은 3 이상 200 이하인 자연수입니다.
  • 지점 s, a, b는 1 이상 n 이하인 자연수이며, 각기 서로 다른 값입니다.
    • 즉, 출발지점, A의 도착지점, B의 도착지점은 서로 겹치지 않습니다.
  • fares는 2차원 정수 배열입니다.
  • fares 배열의 크기는 2 이상 n x (n-1) / 2 이하입니다.
    • 예를들어, n = 6이라면 fares 배열의 크기는 2 이상 15 이하입니다. (6 x 5 / 2 = 15)
    • fares 배열의 각 행은 [c, d, f] 형태입니다.
    • c지점과 d지점 사이의 예상 택시요금이 f원이라는 뜻입니다.
    • 지점 c, d는 1 이상 n 이하인 자연수이며, 각기 서로 다른 값입니다.
    • 요금 f는 1 이상 100,000 이하인 자연수입니다.
    • fares 배열에 두 지점 간 예상 택시요금은 1개만 주어집니다. 즉, [c, d, f]가 있다면 [d, c, f]는 주어지지 않습니다.
  • 출발지점 s에서 도착지점 a와 b로 가는 경로가 존재하는 경우만 입력으로 주어집니다.

 


 
[입출력 예]
n s a b fares result
6 4 6 2 [[4, 1, 10], [3, 5, 24], [5, 6, 2], [3, 1, 41], [5, 1, 24], [4, 6, 50], [2, 4, 66], [2, 3, 22], [1, 6, 25]] 82
7 3 4 1 [[5, 7, 9], [4, 6, 4], [3, 6, 1], [3, 2, 3], [2, 1, 6]] 14
6 4 5 6 [[2,6,6], [6,3,7], [4,6,7], [6,5,11], [2,5,12], [5,3,20], [2,4,8], [4,3,9]] 18


 

입출력 예에 대한 설명

 

 

 

입출력 예 #1


문제 예시와 같습니다.

 

 

 

 

입출력 예 #2

 

 

  • 합승을 하지 않고, B는 3→2→1, A는 3→6→4 경로로 각자 택시를 타고 가는 것이 최저 예상 택시요금입니다.
  • 따라서 최저 예상 택시요금은 (3 + 6) + (1 + 4) = 14원 입니다.

 

 

 

입출력 예 #3

 

 

  • A와 B가 4→6 구간을 합승하고 B가 6번 지점에서 내린 후, A가6→5` 구간을 혼자 타고 가는 것이 최저 예상 택시요금입니다.
  • 따라서 최저 예상 택시요금은 7 + 11 = 18원 입니다.

 

 

 

 

 

나의 코드

 

1. 플로이드 워셜 알고리즘 이용

import java.util.*;

// 플로이드 워셜로 구현 : 각 지점에서의 지점까지의 최솟값을 모두 구한 뒤 (start -> x) + (x -> a) + (x -> b) 의 최솟값을 구한다.
class Solution {
    public int solution(int n, int s, int a, int b, int[][] fares) {
        int answer = Integer.MAX_VALUE;
        
        int[][] dist = new int[n+1][n+1];
        
        // dist 배열 초기화(자기자신한테 경로는 0 , 나머진 절대 나올수 없는 경로값)
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                if(i == j)
                    dist[i][j] = 0;
                else
                    dist[i][j] = 200000001; // 200 * 1000000 보다 큰 수 지정 (Integer.MAX_VALUE로 하면 안됌)
            }
        }
        
        // 간선 정보
        for(int i=0; i<fares.length; i++) {
            dist[fares[i][0]][fares[i][1]] = fares[i][2];
            dist[fares[i][1]][fares[i][0]] = fares[i][2];
        }
        
        // 플로이드 워셜을 이용하여 전체 최소거리를 구한다.
        for(int k=1; k<=n; k++) {
            for(int i=1; i<=n; i++) {
                for(int j=1; j<=n; j++) {
                    dist[i][j] = Math.min(dist[i][j], dist[i][k] + dist[k][j]);
                }
            }
        }
        
        for(int i=1; i<=n; i++) {
            answer = Math.min(answer, dist[s][i] + dist[i][a] + dist[i][b]);
        }
        
        return answer;
    }
}

 

풀이

  1. 플로이드 워셜 알고리즘을 이용하여 모든 지점 사이의 비용을 구하고 (start 지점에서 x 지점) + (x 지점에서 a 지점) + (x지점에서 b 지점) 의 비용이 가장 작은 것을 구하면 된다.
  2. 우선 answer를 가장 큰 수로 초기화 하고 지점과 지점 사이의 비용을 구하기 위해 int형 2차원 배열 dist를 생성한다.
  3. dist[i][j]는 i에서 j로 가는 최소 비용을 업데이트 해가며 구할 것이다.
  4. dist 배열에 자기 자신한테 가는 비용(i == j, dist[i][j])은 0으로 나머지 경우(i != j, dist[i][j])에는 문제의 최대 비용인 200 * 1000000 보다 큰 수인 200000001로 초기화한다. (Integer.MAX_VALUE로 하지 않는 이유는 dist 끼리 더할 때 Integer의 범위를 벗어나게 될 수 있기 때문이다)
  5. dist를 초기화 한 후에는 주어진 간선 정보를 세팅하도록 한다.
  6. 주어진 fares를 돌면서 dist의 해당 지점 사이의 비용을 저장하도록 한다.
  7. 이제 플로이드 워셜 알고리즘을 이용하여 전체 지점과 지점 사이의 최소 비용을 업데이트 하도록 한다.
  8. 3중 for문을 이용하여 dist[i][j]와 dist[i][k] + dist[k][j] 를 비교하여 작은 값을 dist[i][j]에 저장해 나간다. (i 지점에서 k지점을 거쳐 j지점으로 가는 비용을 업데이트 하는 것이다)
  9. 지점과 지점 사이의 최소 비용을 모두 구한 후에는 모든 지점을 for문을 돌면서 (start -> i) + (i -> a) + (i -> b) 이 최소가 될 때의 비용(dist[s][i] + dist[i][a] + dist[i][b])을 구하여 answer에 저장하고 반환하면 된다.
     

 

 

 

 

2. 다익스트라 알고리즘 이용

import java.util.*;

// 다익스트라로 구현 : s에서 각 지점의 최솟값, a에서 각 지점의 최솟값, b에서 각 지점의 최솟값을 구한 뒤 (start -> x) + (x -> a) + (x -> b) 의 최솟값을 구한다.
class Solution {
    ArrayList<Node>[] graph; // 배열 사용
    public int solution(int n, int s, int a, int b, int[][] fares) {
        int answer = Integer.MAX_VALUE;
        
        graph = new ArrayList[n+1];
        
        for(int i=1; i<=n; i++) {
            graph[i] = new ArrayList<>();
        }
        
        for(int i=0; i<fares.length; i++) {
            graph[fares[i][0]].add(new Node(fares[i][1], fares[i][2]));
            graph[fares[i][1]].add(new Node(fares[i][0], fares[i][2]));
        }
        
        int[] distS = dijkstra(s);
        int[] distA = dijkstra(a);
        int[] distB = dijkstra(b);
        
        for(int i=1; i<=n; i++) {
            answer = Math.min(answer, distS[i] + distA[i] + distB[i]);
        }
        
        return answer;
    }
    
    public int[] dijkstra(int start) {
        PriorityQueue<Node> pq = new PriorityQueue<>((o1, o2) -> o1.cost - o2.cost);
        pq.add(new Node(start, 0));
        
        int[] dist = new int[graph.length];
        Arrays.fill(dist, 200000001); // 200 * 1000000 보다 큰 수 지정
        dist[start] = 0;
        
        while(!pq.isEmpty()) {
            Node now = pq.poll();
            
            if(now.cost > dist[now.idx]) continue;
            
            for(Node next : graph[now.idx]) {
                if(dist[now.idx] + next.cost < dist[next.idx]) {
                    dist[next.idx] = dist[now.idx] + next.cost;
                    pq.add(new Node(next.idx, dist[now.idx] + next.cost));
                } 
            }
        }
        
        return dist;
    }
    
    class Node {
        int idx;
        int cost;
        
        Node(int idx, int cost) {
            this.idx = idx;
            this.cost = cost;
        }
    }
}


class Solution2 {
    ArrayList<ArrayList<Node>> graph; // ArrayList 사용
    public int solution(int n, int s, int a, int b, int[][] fares) {
       
        int answer = Integer.MAX_VALUE;
        graph = new ArrayList<>();
        
        for(int i=0; i<=n; i++)
            graph.add(new ArrayList<>());
        
        for(int i=0; i<fares.length; i++) {
            graph.get(fares[i][0]).add(new Node(fares[i][1], fares[i][2]));
            graph.get(fares[i][1]).add(new Node(fares[i][0], fares[i][2]));
        }
        
        int[] distS = dijkstra(s);
        int[] distA = dijkstra(a);
        int[] distB = dijkstra(b);
        
        for(int i=1; i<=n; i++) {
            answer = Math.min(answer, distS[i] + distA[i] + distB[i]);
        }
        
        return answer;
    }
                                        
    public int[] dijkstra(int start) {
        PriorityQueue<Node> pq = new PriorityQueue<>((o1, o2) -> o1.cost - o2.cost);
        pq.offer(new Node(start, 0));
        
        int[] dist = new int[graph.size()];
        Arrays.fill(dist, 200000001); // 200 * 1000000 보다 큰 수 지정
        dist[start] = 0;
        
        while(!pq.isEmpty()) {
            Node now = pq.poll();
            
            if(now.cost > dist[now.idx]) continue;
             
            for(Node next : graph.get(now.idx)) {
                if(dist[now.idx] + next.cost < dist[next.idx]) {
                    dist[next.idx] = dist[now.idx] + next.cost;
                    pq.offer(new Node(next.idx, dist[now.idx] + next.cost));
                }
            }
        }
        
        return dist;
    }
                                        
    public class Node {
        int idx;
        int cost;
        
        public Node(int idx, int cost) {
            this.idx = idx;
            this.cost = cost;
        }
    }
}

 

풀이

  1. 다익스트라 알고리즘은 한 지점에서 다른 모든 지점까지의 최소 비용을 구하는 알고리즘이므로 (start 지점에서 x 지점) + (x 지점에서 a 지점) + (x지점에서 b 지점) 의 비용이 가장 작은 것을 구하기 위해서는 start 지점, a 지점, b 지점 이렇게 세 지점에서 각각 다익스트라 알고리즘을 실행한 뒤에 최소가 되는 비용을 구하면 된다.
  2. 우선 answer를 가장 큰 수로 초기화 한다.
  3. 지점의 번호와 비용을 사용하기 위한 Node 클래스를 만들고 해당 Node를 선언타입으로 하는 ArrayList 배열 graph를 생성한다.
  4. graph의 각 인덱스에는 해당 인덱스 지점에서 연결된 지점으로 갈 수 있는 지점과 비용이 담길 것이다.
  5. 따라서 fares를 for문을 돌면서 graph의 해당 인덱스 지점에서 연결된 지점의 번호와 인덱스를 갖는 Node를 담아주도록 한다.
  6. 그리고 이제 다익스트라 알고리즘을 이용하여 한 지점에서 다른 모든 지점까지의 최소 비용을 업데이트 하면 된다.
  7. s, a, b 각각을 출발점으로 하여 세 번 다익스트라 알고리즘을 이용하여 s, a, b에서 다른 모든 지점까지의 비용을 구해 각각의 1차원 dist 배열에 저장한다.
  8. 다익스트라 알고리즘은 Node를 선언타입으로 하는 우선순위큐를 생성하고 노드의 멤버 변수인 비용에 따라 오름차순 되도록 한다.
  9. 1차원 dist 배열을 만들고 문제의 최대 비용인 200 * 1000000 보다 큰 수인 200000001로 초기화한다. (Integer.MAX_VALUE로 하지 않는 이유는 dist에 다른 값을 더할 때 Integer의 범위를 벗어나게 될 수 있기 때문이다)
  10. 우선순위큐에 출발점과 비용을 0으로 하는 노드를 생성하여 담고 dist[출발점]을 0으로 한다.(자기 자신한테 가는 비용)
  11. 이제 우선순위큐가 빌 때까지 while문을 돌면서 우선순위큐의 첫 데이터를 꺼내고 해당 노드의 비용과 해당 노드의 dist 값과 비교하여 해당 노드의 비용이 더 높다면 업데이트 할 필요가 없기 때문에 넘어가고 아니라면 해당 노드의 번호와 연결된 다른 지점들을 for each문을 돌면서 (dist[현재 노드까지의 비용] + 지금 노드에서 다음 노드와의 비용)이 dist[다음 노드의 번호] 보다 작다면 최소 비용으로 업데이트 해야하므로 dist[다음 노드의 번호]에 해당 (dist[현재 노드까지의 비용] + 지금 노드에서 다음 노드와의 비용)을 저장하고 우선순위큐에 다음 노드의 번호와 (dist[현재 노드까지의 비용] + 지금 노드에서 다음 노드와의 비용)으로 하는 Node를 생성하여 담는다.
  12. 이렇게 while문을 반복하며 우선순위큐가 빌 때까지 출발점에서 각 지점까지의 최소비용을 구하면 된다.
  13. s, a, b를 출발점으로 하여 각 노드와의 최소 비용을 구한 각각의 1차원 배열 distS, distA, distB 를 이용하여  distS[i] + distA[i] + distB[i] 가 최소가 되는 비용을 구해 answer에 저장하고 반환하면 된다.

 

 

 

 

'Programmers' 카테고리의 다른 글

[프로그래머스 Level.3] 섬 연결하기 (탐욕법(Greedy)) (Java)  (0) 2023.03.31
[프로그래머스 Level.3] 파괴되지 않은 건물 (2022 KAKAO BLIND RECRUITMENT) (Java)  (0) 2023.03.30
[프로그래머스 Level.3] 아이템 줍기 (깊이/너비 우선 탐색(DFS/BFS)) (Java)  (0) 2023.03.28
[프로그래머스 Level.2] 광물 캐기 (연습 문제) (Java)  (0) 2023.03.28
[프로그래머스 Level.2] 당구 연습 (연습 문제) (Java)  (0) 2023.03.27
  • 문제 링크
  • 코딩테스트 연습 > 2021 KAKAO BLIND RECRUITMENT > 합승 택시 요금
  • 나의 코드
  • 풀이
  • 풀이
'Programmers' 카테고리의 다른 글
  • [프로그래머스 Level.3] 섬 연결하기 (탐욕법(Greedy)) (Java)
  • [프로그래머스 Level.3] 파괴되지 않은 건물 (2022 KAKAO BLIND RECRUITMENT) (Java)
  • [프로그래머스 Level.3] 아이템 줍기 (깊이/너비 우선 탐색(DFS/BFS)) (Java)
  • [프로그래머스 Level.2] 광물 캐기 (연습 문제) (Java)
Devtraces
Devtraces

티스토리툴바

단축키

내 블로그

내 블로그 - 관리자 홈 전환
Q
Q
새 글 쓰기
W
W

블로그 게시글

글 수정 (권한 있는 경우)
E
E
댓글 영역으로 이동
C
C

모든 영역

이 페이지의 URL 복사
S
S
맨 위로 이동
T
T
티스토리 홈 이동
H
H
단축키 안내
Shift + /
⇧ + /

* 단축키는 한글/영문 대소문자로 이용 가능하며, 티스토리 기본 도메인에서만 동작합니다.