https://www.acmicpc.net/problem/2056
문제
수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다.
몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해 반드시 먼저 완료되어야 할 작업들이 있다. 이 작업들은 번호가 아주 예쁘게 매겨져 있어서, K번 작업에 대해 선행 관계에 있는(즉, K번 작업을 시작하기 전에 반드시 먼저 완료되어야 하는) 작업들의 번호는 모두 1 이상 (K-1) 이하이다. 작업들 중에는, 그것에 대해 선행 관계에 있는 작업이 하나도 없는 작업이 반드시 하나 이상 존재한다. (1번 작업이 항상 그러하다)
모든 작업을 완료하기 위해 필요한 최소 시간을 구하여라. 물론, 서로 선행 관계가 없는 작업들은 동시에 수행 가능하다.
입력
첫째 줄에 N이 주어진다.
두 번째 줄부터 N+1번째 줄까지 N개의 줄이 주어진다. 2번째 줄은 1번 작업, 3번째 줄은 2번 작업, ..., N+1번째 줄은 N번 작업을 각각 나타낸다. 각 줄의 처음에는, 해당 작업에 걸리는 시간이 먼저 주어지고, 그 다음에 그 작업에 대해 선행 관계에 있는 작업들의 개수(0 ≤ 개수 ≤ 100)가 주어진다. 그리고 선행 관계에 있는 작업들의 번호가 주어진다.
출력
첫째 줄에 모든 작업을 완료하기 위한 최소 시간을 출력한다.
풀이
풀이 1. 위상 정렬
기본적인 위상 정렬 알고리즘대로 푼다.
다만, 새로운 작업을 시작하는 시간은 다른 배열을 통해 저장해야 한다: BFS에서 indegree가 0이 되는 순간 그 다음 일을 진행하는데, indegree가 0이 되는 순간에 한 일보다 다른 일까지의 소요시간이 더 길 수도 있기 때문이다.
풀이 2. dp
문제 조건을 따져보면, 문제는 dp를 기본적인 풀이 방법으로 요구한 듯하다. 1~N까지 순서대로 따지면 된다.
코드
풀이 1
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i <= N; i++) {
graph.add(new ArrayList<Integer>());
}
int[] indegree = new int[N+1];
int[] time = new int[N+1];
for (int i = 1; i <= N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
time[i] = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
for (int j = 0; j < M; j++) {
int prev = Integer.parseInt(st.nextToken());
graph.get(prev).add(i);
indegree[i]++;
}
}
int[] dp = new int[N+1];
Queue<int[]> queue = new ArrayDeque<>();
for (int i = 1; i <= N; i++) {
if (indegree[i] == 0) {
queue.offer(new int[] {i, time[i]});
dp[i] = time[i];
}
}
while (!queue.isEmpty()) {
int[] cur = queue.poll();
int loc = cur[0], dist = cur[1];
for (int nxtLoc: graph.get(loc)) {
indegree[nxtLoc]--;
dp[nxtLoc] = Math.max(dp[nxtLoc], dist + time[nxtLoc]);
if (indegree[nxtLoc] == 0) {
queue.offer(new int[] {nxtLoc, dp[nxtLoc]});
}
}
}
int ans = 0;
for (int i = 1; i <= N; i++) {
if (dp[i] > ans) ans = dp[i];
}
System.out.println(ans);
}
}
풀이 2
import java.io.*;
import java.util.*;
public class Main {
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
int N = Integer.parseInt(br.readLine());
List<List<Integer>> graph = new ArrayList<>();
for (int i = 0; i <= N; i++) {
graph.add(new ArrayList<Integer>());
}
int[] dp = new int[N+1];
int[] time = new int[N+1];
for (int i = 1; i <= N; i++) {
StringTokenizer st = new StringTokenizer(br.readLine());
time[i] = Integer.parseInt(st.nextToken());
int M = Integer.parseInt(st.nextToken());
for (int j = 0; j < M; j++) {
int prev = Integer.parseInt(st.nextToken());
graph.get(i).add(prev);
}
}
for (int cur = 1; cur <= N; cur++) {
dp[cur] = time[cur];
for (int prev: graph.get(cur)) {
dp[cur] = Math.max(dp[cur], dp[prev] + time[cur]);
}
}
int ans = 0;
for (int i = 1; i <= N; i++) {
if (dp[i] > ans) ans = dp[i];
}
System.out.println(ans);
}
}
'PS > DP' 카테고리의 다른 글
프로그래머스: N으로 표현 (Java) (0) | 2022.06.28 |
---|---|
백준 2098번: 외판원 순회 (Java) (0) | 2022.06.27 |
백준 2342번: Dance Dance Revolution (JAVA) (0) | 2022.05.18 |
백준 17070번: 파이프 옮기기 1 (JAVA) (0) | 2022.05.17 |
백준 2629번: 양팔저울 (JAVA) (0) | 2022.04.25 |