밤늦게 귀가할 때 안전을 위해 항상 택시를 이용하던 무지는 최근 야근이 잦아져 택시를 더 많이 이용하게 되어 택시비를 아낄 수 있는 방법을 고민하고 있습니다. "무지"는 자신이 택시를 이용할 때 동료인 어피치 역시 자신과 비슷한 방향으로 가는 택시를 종종 이용하는 것을 알게 되었습니다. "무지"는 "어피치"와 귀가 방향이 비슷하여 택시 합승을 적절히 이용하면 택시요금을 얼마나 아낄 수 있을 지 계산해 보고 "어피치"에게 합승을 제안해 보려고 합니다.
정리 하자면 S 지점에서 둘 다 출발해 어느 한 지점까지 합승 후 각각 A, B로 헤어질 때 가장 적은 택시요금을 구하여라 이다. 다익스트라를 써야한다!!
합승을 어느지점까지 해야할지 모르는 상황이다. 그렇다면, 모든 경우를 비교해줘야한다.
1 ~ n 각각의 지점까지 합승하는 경우를 다 비교해주면 된다.
i 지점 까지 합승 한 비용 = S 에서 i 지점까지 가는 최소 비용
i 지점에서 A 지점까지의 비용 = i 에서 A 지점까지 가는 최소 비용
i 지점에서 B 지점까지의 비용 = i 에서 B 지점까지 가는 최소 비용
다시 정리하면, S, A, B에 대해서 각각 1 ~ n 지점까지의 최소 비용들을 구하고 구한 비용의 합 들 중 가장 작은 것을 출력해주면 된다.
//다익스트라
import java.util.*;
class Solution {
static LinkedList<Node>[] doro;
public int solution(int n, int s, int a, int b, int[][] fares) {
int answer = 0;
//도로 정보 정리
doro = new LinkedList[n+1];
for(int i = 1; i <= n; i++) doro[i] = new LinkedList<>();
for(int[] v : fares){
doro[v[0]].add(new Node(v[1], v[2]));
doro[v[1]].add(new Node(v[0], v[2]));
}
answer = getMinTaxiFare(s,a,b);
return answer;
}
private static int getMinTaxiFare(int s, int a, int b){
int maxV = 20000001;
int doroLength = doro.length;
//S, A, B 들의 1 ~ n 지점까지의 최소비용 배열을 만들어준다
int[] arrS = new int[doroLength];
int[] arrA = new int[doroLength];
int[] arrB = new int[doroLength];
Arrays.fill(arrS, maxV);
Arrays.fill(arrA, maxV);
Arrays.fill(arrB, maxV);
dijkstra(s, arrS);
dijkstra(a, arrA);
dijkstra(b, arrB);
int res = maxV;
for(int i = 1 ; i < doroLength ; i++){
//i지점까지 합승 후 각각 A, B로 나뉘는 경우
res = Math.min(res, arrS[i] + arrA[i] + arrB[i]);
}
return res;
}
private static void dijkstra(int start, int[] arr){
PriorityQueue<Node> mq = new PriorityQueue<>();
mq.offer(new Node(start, 0));
arr[start] = 0;
while(!mq.isEmpty()){
Node cur = mq.poll();
int curN = cur.num;
int curW = cur.weight;
// 현재까지의 비용이 최단 비용의 값보다 크다면,
// 그 경로는 사용할 필요가 없으니 continue;
if(curW > arr[curN]) continue;
for(int i = 0; i < doro[curN].size(); i++){
if(arr[doro[curN].get(i).num] > curW + doro[curN].get(i).weight){
arr[doro[curN].get(i).num] = curW + doro[curN].get(i).weight;
mq.offer(new Node(doro[curN].get(i).num,
curW+doro[curN].get(i).weight));
}
}
}
}
static class Node implements Comparable<Node>{
int num , weight;
public Node(int num, int weight){
this.num = num;
this.weight = weight;
}
public int compareTo(Node o){
return this.weight - o.weight;
}
}
}
다익스트라 방법 말고 하나가 더 생각이 날 것이다. 각 지점 사이의 최소비용을 구하는 것이므로 플로이드 와샬 알고리즘을 사용해도 된다.
//플로이드 와샬
import java.util.*;
class Solution {
public int solution(int n, int s, int a, int b, int[][] fares) {
int answer = 20000001;
int[][] arr = new int[n+1][n+1];
for(int i = 1 ; i < n + 1; i++){
Arrays.fill(arr[i], 20000001);
arr[i][i] = 0;
}
//행렬 정보 생성
for(int[] ae : fares){
arr[ae[0]][ae[1]] = ae[2];
arr[ae[1]][ae[0]] = ae[2];
}
//i,j,k 각각 다를 경우만 계산 하도록 if 조건을넣어줬다.
for(int k = 1; k < n + 1; k++){
for(int i = 1 ; i < n + 1; i++){
if(k == i) continue;
for(int j = 1; j < n + 1; j++){
if(i != j && k != j && arr[i][j] > arr[i][k] + arr[k][j])
arr[i][j] = arr[i][k] + arr[k][j];
}
}
}
for(int i = 1; i < n + 1 ;i++)
answer = Math.min(answer, arr[s][i] + arr[i][a] + arr[i][b]);
return answer;
}
}
정확성 테스트에서는 플로이드 와샬이 더 빠르게 나왔지만
효율성 테스트에서는 다익스트라가 더 빠르게 나왔다.
플로이드 와샬은 일단 행렬을 만들어서 계산하고 모든 경우의 값을 다 비교하기 때문에
다익스트라 보다 효율성이 낮을것이다.
끝!