본문 바로가기
Study (etc)/Problem Solving

[BOJ / C++] 2056번 : 작업

by Haren 2023. 9. 20.

문제

수행해야 할 작업 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)가 주어진다. 그리고 선행 관계에 있는 작업들의 번호가 주어진다.

출력

첫째 줄에 모든 작업을 완료하기 위한 최소 시간을 출력한다.

Solved.ac 레벨

골드 IV

풀이

DP와 함께 위상 정렬을 활용하는 문제다.

작업 1개에는 선행되어야 하는 작업이 1개 이상 존재하는데, 임의의 작업 1개를 나타내는 노드에 접근하기 위한 진입 차수는 선행되어야 하는 작업의 갯수와 같다. 따라서 위상 정렬을 활용하여 진입 차수를 0으로 만들어나가며 소요되는 시간을 더해주면 된다.

 

소요 시간이 최소가 되어야 하는데 결국 모든 일을 해치워야 하고, 선행 관계가 없는 일은 동시에 수행할 수 있다.

그래서 한 작업의 선행 작업 중 수행 시간이 가장 긴 작업을의 시간을 더해 주었다. 여기서 DP를 활용할 수 있다.

Code

#include <bits/stdc++.h>
#define MAX 10001

using namespace std;

int n, ans = 0;
vector<int> WORK[MAX];
int workTime[MAX];
int inDegree[MAX];
int dp[MAX];

void topologySort() {
    queue<int> q;

    for(int i = 1; i <= n; i++) {
        if(inDegree[i] == 0) {
            q.push(i);
            dp[i] = workTime[i];
        }
    }

    while(!q.empty()) {
        int cur = q.front();
        ans = max(ans, dp[cur]);
        q.pop();

        for(int i = 0; i < WORK[cur].size(); i++) {
            int nxt = WORK[cur][i];
            dp[nxt] = max(dp[nxt], dp[cur] + workTime[nxt]);

            if(--inDegree[nxt] == 0) q.push(nxt);
        }
    }
}

int main() {
    ios::sync_with_stdio(0);
    cin.tie(0);
    cout.tie(0);

    cin >> n;

    for(int i = 1; i <= n; i++) {
        int time, cnt;
        cin >> time >> cnt;
        workTime[i] = time;
        inDegree[i] = cnt;

        for(int j = 1; j <= cnt; j++) {
            int tmp;
            cin >> tmp;
            WORK[tmp].push_back(i);
        }
    }

    topologySort();

    cout << ans << "\n";

    return 0;
}
 

2056번: 작업

수행해야 할 작업 N개 (3 ≤ N ≤ 10000)가 있다. 각각의 작업마다 걸리는 시간(1 ≤ 시간 ≤ 100)이 정수로 주어진다. 몇몇 작업들 사이에는 선행 관계라는 게 있어서, 어떤 작업을 수행하기 위해

www.acmicpc.net