📌 문제 링크 - https://www.acmicpc.net/problem/2611
문제
자동차 경주로는 <그림 1>의 예와 같이 표현된다. 화살표는 각 지점을 잇는 도로를 의미하며 모든 도로는 일방통행 도로로 화살표 방향으로만 움직일 수 있다.
자동차 경주의 코스는 1번 지점에서 출발하여 다시 1번 지점으로 되돌아오는 것이다. 단, 중간에는 1번 지점을 지나서는 안 된다. 경주로는 1번 지점을 제외한 어느 지점에서 출발하여도 1번 지점을 지나가지 않고서는 같은 지점으로 돌아올 수 없도록 되어 있다. 또한 1번 지점에서 다른 모든 지점으로 갈 수 있고, 다른 모든 지점에서 1번 지점으로 갈 수 있다.
각 도로에는 <그림 2>의 예와 같이 그 도로를 지날 때 얻는 점수가 있다.
1번 지점에서 출발하여 가장 많은 점수를 얻어 다시 1번 지점으로 돌아오는 팀이 우승을 하게 된다. 가장 많은 점수를 얻어 1번 지점으로 돌아오는 경로를 찾아 그 얻는 점수와 경로를 출력하는 프로그램을 작성하시오.
입력
첫째 줄에는 지점의 개수 N이 주어진다. 각 지점에는 1부터 N까지의 서로 다른 번호가 부여된다. 둘째 줄에는 도로의 개수 M이 주어진다. 이어 M개의 줄에는 p ,q ,r의 형식으로 도로의 정보가 주어지는데 이는 p번 지점부터 q번 지점으로 갈 수 있는 도로가 있고 그 도로에 부여된 점수가 r이라는 뜻이다. N은 1000이하의 자연수이고, p와 q는 1이상의 N이하의 자연수이며 r은 100이하의 자연수 이다. p와 q는 같지 않다.
출력
가장 많은 점수를 얻은 경로를 찾아, 첫째 줄에는 그 얻는 점수를 출력하고 둘째 줄에는 그 경로를 출력한다. 경로를 출력할 때는 지나는 지점들의 번호를 사이에 한 칸의 공백을 두어 출력한다. 출력하는 경로는 반드시 1번 지점에서 시작하여 1번 지점으로 끝나야 한다. 만약 같은 점수를 얻는 경로가 둘 이상일 경우 그 중 하나만 출력하면 된다.
풀이
다이나믹 프로그래밍을 활용한 위상 정렬 문제다.
while(M-- > 0) {
st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken());
int to = Integer.parseInt(st.nextToken());
int score = Integer.parseInt(st.nextToken());
roadList.get(from).add(new int[] {to, score});
inDegree[to]++;
}
입력 받을 때, 양방향이 아닌 일방통행 도로이므로, 단방향으로 도로 정보를 roadList에 저장하며, 도착 지점(to)에 들어오는 간선 개수를 inDegree에 기록한다.
for(int[] next : roadList.get(cur)) {
int node = next[0]; // 다음 지점
int score = next[1] + maxScore[cur]; // 다음 지점으로 갈 경우 점수
if(maxScore[node] < score) {
maxScore[node] = score;
prev[node] = cur;
}
if(--inDegree[node] == 0) {
q.offer(node);
}
}
이후, 시작 지점(1번)을 큐에 넣고 탐색을 시작한다.
현재 지점에서 다음 지점(node)으로 이동했을 때 얻는 점수가 기존의 maxScore[node]보다 크다면, 점수를 갱신하고, 경로 정보(prev[node])도 현재 지점으로 갱신한다.
탐색한 간선을 처리하면서, 해당 도착 지점의 진입 차수(inDegree)를 감소시키고, 만약 진입 차수가 0이 되었다면 큐에 추가한다.
마지막으로 prev를 활용하여 경로를 추적하여 출력하면 된다.
코드
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.*;
/*
https://www.acmicpc.net/problem/2611
1번 지점에서 출발하여 가장 많은 점수를 얻어 다시 1번 지점으로 돌아오는 팀이 우승
*/
public class Main_2611 {
private static final int START = 1; // 출발지
private static int[] maxScore; // 지점 별 최대 점수
private static int[] inDegree; // 각 지점의 진입 차수
private static int[] prev; // 이전 지점
private static List<List<int[]>> roadList; // 길 정보
public static void main(String[] args) throws IOException {
init();
getMaxScore();
print();
}//main
private static void getMaxScore() {
Queue<Integer> q = new LinkedList<>();
q.offer(START);
int cur;
while(!q.isEmpty()) {
cur = q.poll();
// 1번 지점에서 시작하여 1번 지점으로 끝나야 한다
if(cur == START && inDegree[START] == 0) break;
for(int[] next : roadList.get(cur)) {
int node = next[0]; // 다음 지점
int score = next[1] + maxScore[cur]; // 다음 지점으로 갈 경우 점수
if(maxScore[node] < score) {
maxScore[node] = score;
prev[node] = cur;
}
if(--inDegree[node] == 0) {
q.offer(node);
}
}
}
}//getMaxScore
private static void print() {
StringBuilder ans = new StringBuilder();
Stack<Integer> path = new Stack<>();
int cur = START;
while(true) {
path.add(cur);
if(prev[cur] == START) {
path.add(START);
break;
}
cur = prev[cur];
}
// 첫째 줄에는 점수를 출력
ans.append(maxScore[START]).append('\n');
// 둘째 줄에는 경로를 출력
while(!path.isEmpty()) {
ans.append(path.pop()).append(' ');
}
System.out.print(ans);
}//print
private static void init() throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
int M = Integer.parseInt(br.readLine());
roadList = new ArrayList<>(N+1);
maxScore = new int[N+1];
inDegree = new int[N+1];
prev = new int[N+1];
for(int i=0; i<=N; i++) {
roadList.add(new ArrayList<>());
}
StringTokenizer st;
while(M-- > 0) {
st = new StringTokenizer(br.readLine());
int from = Integer.parseInt(st.nextToken());
int to = Integer.parseInt(st.nextToken());
int score = Integer.parseInt(st.nextToken());
roadList.get(from).add(new int[] {to, score});
inDegree[to]++;
}
br.close();
}//init
}//class
'Algorithm > 백준' 카테고리의 다른 글
[Java] 백준 6209. 제자리 멀리뛰기 (0) | 2025.01.02 |
---|---|
[Java] 백준 1202. 보석 도둑 (0) | 2024.12.25 |
[Java] 백준 19645. 햄최몇? (0) | 2024.12.16 |
[Java] 백준 9997. 폰트 (0) | 2024.12.05 |
[Java] 백준 24428. 알고리즘 수업 - 행렬 경로 문제 5 (0) | 2024.12.02 |