티스토리 뷰
https://programmers.co.kr/learn/courses/30/lessons/72413
코딩테스트 연습 - 합승 택시 요금
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
programmers.co.kr
✔ 문제 조건
- n개의 지점 (1번~n번)
- 간선은 두 지점 사이의 거리 (택시요금), 양방향 그래프
- A와 B는 합승 가능하다. i번째 지점까지 합승했다면 총 비용은 A,B가 i번째 지점까지 합승했을 때 비용 + i에서 A, B 지점까지 각각 발생하는 비용의 합이다.
- 합승하지 않았을 때 비용이 더 저렴하다면 합승하지 않아도 된다.
- A, B가 S에서 각자의 도착 지점까지 택시를 타고 갈 때 발생하는 최저 예상 택시 요금을 구하시오
✔ 접근 과정
- 플루이드 워샬 알고리즘으로, 각 지점 간의 최소 이동 비용을 구한다.
- 합승하지 않았을 때의 최소 비용을 구한다:
S->A
+S->B
- 합승했을 때의 최소 비용을 구한다.
1~N번 정점을 각각 경유하여 가는 경우:S->경유지
+경유지->A
+경유지->B
- 2번 비용과 3번 비용 중 최소 비용을 구하여 리턴한다.
✔ 주의할 점
- 합승하지 않았을 때의 비용을 따로 구해야 한다고 생각했지만 플루이드 워샬 알고리즘을 위해 가중치 인접 행렬 전체를 구하기 때문에 따로 구하지 않아도 되었다.
- 플루이드 워샬 알고리즘을 위해 인접 행렬을 최대값으로 초기화 하기 때문에 연산 오류가 발생한다. 경유 했을 경우를 위해 최대값 끼리 더했을 때 정수 범위를 넘어가서 음수로 표기되기 때문이다. 해결법은 다음과 같다.
- 연산 오류가 발생하지 않는 최대값을 설정한다.
요금 f의 최대값은 100,000이고, 지점 개수의 최대값은 200이다. 모든 지점을 경유했을 때의 최대값은 200 * 100,000이다. 따라서 최대값을 200 * 100,000+1으로 초기화하면 최대값끼리 더해도 정수 범위 내이기 때문에 연산 오류가 나지 않는다. - 최대값 끼리 연산하는 경우를 없앤다.
연산 오류가 발생하는 부분은, 1) 플루이드 워샬 알고리즘 내에서 어떤 지점을 경유했을 때의 비용이 더 적은지를 살펴볼 때 2) 최종 답을 구하기 위해 각 정점을 경유하여 가는 경유의 비용을 살펴볼 때 두 부분이다.
이때adjMatrix[i][j]==INF
라면i
,j
는 인접하지 않은 경우기 때문에 살펴볼 필요가 없다. 따라서 continue로 처리한다.
- 연산 오류가 발생하지 않는 최대값을 설정한다.
- 인접행렬에서
adjMatrix[S][S]==0
이기 때문에 접근 과정의 2번을 굳이 실행하지 않아도, 합승하지 않았을 때의 요금이 3번에서 구해지지만 코드 가독성을 위해 추가했다. 어차피min
값을 초기화하긴 해야하니까..
import java.util.*;
// 210514
class Solution_LV3_합승택시요금 {
public static void main(String[] args) {
int n = 6, s = 4, a = 6, b = 2;
int[][] fares = new int[][] {
{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}
};
System.out.println(solution(n, s, a, b, fares));
}
static public int solution(int n, int s, int a, int b, int[][] fares) {
// 1. 모든 정점들 사이의 인접 행렬 만들기 & 양방향 그래프
int INF = 987654321;
// int INF = 100000 * 200 + 1;
int[][] adjMatrix = new int[n+1][n+1];
for(int i=0; i<=n; i++) {
Arrays.fill(adjMatrix[i], INF);
adjMatrix[i][i] = 0;
}
for(int[] fare: fares) {
int from = fare[0], to = fare[1], cost = fare[2];
adjMatrix[from][to] = cost;
adjMatrix[to][from] = cost;
}
// 2. 플루이드 워샬 알고리즘 : 경, 출, 도
for(int k=1; k<=n; k++) {
for(int i=1; i<=n; i++) {
if(k==i) continue;
for(int j=1; j<=n; j++) {
if(k==j || i==j) continue;
if(adjMatrix[i][k]==INF || adjMatrix[k][j]==INF) continue;
if(adjMatrix[i][j] > adjMatrix[i][k] + adjMatrix[k][j]) {
adjMatrix[i][j] = adjMatrix[i][k] + adjMatrix[k][j];
}
}
}
}
// 3. 합승하지 않고 바로 가는 경우: S->A + S->B
int min = adjMatrix[s][a] + adjMatrix[s][b];
// INF로 초기화 해도 상관없음 adhMatrix[S][S]는 0이기 때문에 합승하지 않는 경우가 4번에서도 구해짐
// 4. 1~N번 정점을 각각 경유하여 가는 경우: S->경유지 + 경유지->A + 경유지->B
for(int i=1; i<=n; i++) {
if(adjMatrix[s][i]==INF || adjMatrix[i][a]==INF || adjMatrix[i][b]==INF) continue;
min = Math.min(min, adjMatrix[s][i] + adjMatrix[i][a] + adjMatrix[i][b]);
}
return min;
}
}
* 우선순위큐와 다익스트라로 최단 거리 구하는 방법
'코딩테스트 > 프로그래머스' 카테고리의 다른 글
[Programmers] LV2. 단체사진 찍기 (0) | 2021.06.20 |
---|---|
[Programmers] LV3. 광고 삽입 (0) | 2021.05.15 |
[Programmers] LV2. 순위 검색 (0) | 2021.05.13 |
[Programmers] LV3. 보석쇼핑 (0) | 2021.05.06 |
프로그래머스 level 2 - 더 맵게 (힙 Heap) (0) | 2020.11.18 |
댓글