[Baekjoon 1238번] 파티 문제 (with 자바)

반응형
728x90
반응형

문제

https://www.acmicpc.net/problem/1238

 

1238번: 파티

첫째 줄에 N(1 ≤ N ≤ 1,000), M(1 ≤ M ≤ 10,000), X가 공백으로 구분되어 입력된다. 두 번째 줄부터 M+1번째 줄까지 i번째 도로의 시작점, 끝점, 그리고 이 도로를 지나는데 필요한 소요시간 Ti가 들어

www.acmicpc.net

 

 

 

 

다익스트라 알고리즘

https://devfunny.tistory.com/641?category=905091 

 

최단 경로 알고리즘 - 다익스트라 알고리즘 우선순위 큐 사용 버전

들어가기전 기본 다익스트라 알고리즘에 대해 먼저 공부하자. https://devfunny.tistory.com/638 최단 경로 알고리즘 - 다익스트라 알고리즘 기본 버전 최단 경로 알고리즘 (Shortest Path) 가장 짧은 경로를

devfunny.tistory.com

 

 

 

 

풀이코드

package com.algorithm._00_._Current;

import java.util.*;
import java.util.stream.IntStream;

/**
 * @Date 2022/03/15
 * @URL https://www.acmicpc.net/problem/1238
 */
public class _1238_파티 {
    /* 무한을 의미하는 값으로 10억을 설정 */
    public static final int INF = (int) 1e9;

    public static int n; // 노드의 개수(N)
    public static int m; // 간선의 개수(M)
    public static int start; // 시작 노드 번호(Start)

    /* 각 노드에 연결되어 있는 노드에 대한 정보를 담는 배열 */
    public static List<List<QueueNode>> graph = new ArrayList<>();
    public static List<List<QueueNode>> reverseGraph = new ArrayList<>();

    /* 최단 거리 테이블 만들기 */
    public static int[] d = new int[100001];
    public static int[] rd = new int[100001];


    public static void main(String[] args) {
	    // write your code here
        _1238_파티 main = new _1238_파티();
        main.solution();
    }

    public void solution() {
        input();

        /* 다익스트라 알고리즘을 수행 */
        /** 1) 2번 노드 -> 다른 노드들에 대한 최단 거리 */
        dijkstra(graph, d, start);

        /** 2) 다른 노드 -> 2번 노드로 가는 최단 거리 */
        dijkstra(reverseGraph, rd, start);

        /* 합의 max 출력 */
        Optional<Integer> max = IntStream.range(0, n + 1)
                .filter(i -> d[i] != INF && rd[i] != INF)
                .mapToObj(i -> d[i] + rd[i])
                .max(Integer::compareTo);

        System.out.println(max.get());
    }

    private static void dijkstra(List<List<QueueNode>> graph, int[] d, int start) {
        /* 우선순위 큐 선언 */
        PriorityQueue<QueueNode> pq = new PriorityQueue<>();

        /* 시작 노드로 가기 위한 최단 경로는 0으로 설정하여, 큐에 삽입 */
        pq.offer(new QueueNode(start, 0));
        d[start] = 0;

        /* 큐가 비어있지않을 때까지 반복 */
        while(!pq.isEmpty()) {
            /* 가장 최단 거리가 짧은 노드에 대한 정보 꺼내기 */
            QueueNode node = pq.poll();

            int dist = node.getDistance(); // 현재 노드까지의 비용
            int now = node.getIndex(); // 현재 노드 번호

            /* 현재 노드가 이미 처리된 적이 있는 노드라면 무시 */
            if (d[now] < dist) {
                continue;
            }

            /* 현재 노드와 연결된 다른 인접한 노드들을 확인 */
            for (int i = 0; i < graph.get(now).size(); i++) {
                /* 현재의 최단거리 + 현재의 연결된 노드의 비용 */
                int cost = d[now] + graph.get(now).get(i).getDistance();

                /* 현재 노드를 거쳐서 다른 노드로 이동하는 거리가 더 짧은 경우 */
                if (cost < d[graph.get(now).get(i).getIndex()]) {
                    d[graph.get(now).get(i).getIndex()] = cost;
                    pq.offer(new QueueNode(graph.get(now).get(i).getIndex(), cost));
                }
            }
        }
    }

    private static void input() {
        Scanner sc = new Scanner(System.in);

        n = sc.nextInt(); // 노드의 개수(N)
        m = sc.nextInt(); // 간선의 개수(M)
        start = sc.nextInt(); // 시작 노드 번호(Start)

        /* 그래프 초기화 */
        for (int i = 0; i <= n; i++) {
            graph.add(new ArrayList<QueueNode>());
            reverseGraph.add(new ArrayList<QueueNode>());
        }

        /* 모든 간선 정보를 입력받기 */
        for (int i = 0; i < m; i++) {
            int a = sc.nextInt();
            int b = sc.nextInt();
            int c = sc.nextInt();

            /* a번 노드에서 b번 노드로 가는 비용이 c라는 의미 */
            graph.get(a).add(new QueueNode(b, c));
            reverseGraph.get(b).add(new QueueNode(a, c));
        }

        /* 최단 거리 테이블을 모두 무한으로 초기화 */
        d = new int[n + 1];
        rd = new int[n + 1];
        Arrays.fill(d, INF);
        Arrays.fill(rd, INF);
    }
}

class QueueNode implements Comparable<QueueNode> {

    private int index;
    private int distance;

    public QueueNode(int index, int distance) {
        this.index = index;
        this.distance = distance;
    }

    public int getIndex() {
        return this.index;
    }

    public int getDistance() {
        return this.distance;
    }

    // 거리(비용)가 짧은 것이 높은 우선순위를 가지도록 설정
    @Override
    public int compareTo(QueueNode other) {
        if (this.distance < other.distance) {
            return -1;
        }
        return 1;
    }
}

 

 

1) 문제 이해

기존 다익스트라 알고리즘의 문제와 다른 부분은 아래와 같다.

모든 학생들은 집에서 X에 갈수 있고, X에서 집으로 돌아올 수 있는 데이터만 입력으로 주어진다.
...
첫 번째 줄에 N명의 학생들 중 오고 가는데 가장 오래 걸리는 학생의 소요시간을 출력한다.

 

위 문제를 보고 시작 노드 X에서 다른 노드까지의 최단 거리와 추가로, 다른 노드에서 시작 노드 X까지의 최단 거리를 구해야함을 알아야한다.

 

1) X -> 다른 노드
2) 다른 노드 -> X

 

1)번과 2)번의 경우를 더한 값의 최댓값을 출력하면 된다.

 

 

2) 구현 코드

2가지를 구하기 위해 기존 다익스트라 알고리즘 코드에서 리스트와 dp 배열을 2개씩 생성했다.

/* 각 노드에 연결되어 있는 노드에 대한 정보를 담는 배열 */
public static List<List<QueueNode>> graph = new ArrayList<>();
public static List<List<QueueNode>> reverseGraph = new ArrayList<>();

/* 최단 거리 테이블 만들기 */
public static int[] d = new int[100001];
public static int[] rd = new int[100001];

 

input() 에서도 2개씩 초기화하고 데이터를 담는다.

/* a번 노드에서 b번 노드로 가는 비용이 c라는 의미 */
graph.get(a).add(new QueueNode(b, c));
reverseGraph.get(b).add(new QueueNode(a, c));

/* 최단 거리 테이블을 모두 무한으로 초기화 */
d = new int[n + 1];
rd = new int[n + 1];

Arrays.fill(d, INF);
Arrays.fill(rd, INF);

 

dijkstra() 함수를 총 2번 호출한다.

public void solution() {
    input();

    /* 다익스트라 알고리즘을 수행 */
    /** 1) 2번 노드 -> 다른 노드들에 대한 최단 거리 */
    dijkstra(graph, d, start);

    /** 2) 다른 노드 -> 2번 노드로 가는 최단 거리 */
    dijkstra(reverseGraph, rd, start);

    ...
}

 

 

3) 결과 출력

/* 합의 max 출력 */
Optional<Integer> max = IntStream.range(0, n + 1)
        .filter(i -> d[i] != INF && rd[i] != INF)
        .mapToObj(i -> d[i] + rd[i])
        .max(Integer::compareTo);

System.out.println(max.get());

 

 

 

반응형

Designed by JB FACTORY