본문 바로가기

Coding Test

백준 2056 작업 (C++)

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

#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>

using namespace std;

vector<int> g[10001];
vector<int> t;
vector<int> indeg;
vector<int> res;

int main() {

    ios::sync_with_stdio(false);
    cin.tie(NULL);
    cout.tie(NULL);

    int n;
    int ans = -1;

    cin >> n;

    t.resize(n + 1);
    indeg.resize(n + 1, 0);

    for (int i = 1; i <= n; i++) {

        cin >> t[i];

        int inCnt;
        cin >> inCnt;

        for (int j = 0; j < inCnt; j++) {
            int temp;
            cin >> temp;
            g[temp].push_back(i);
            indeg[i]++;
        }
    }

    queue<int> q;
    res.resize(n + 1);

    for (int i = 1; i <= n; i++) {
        if (!indeg[i]) {
            q.push(i);
        }
        res[i] = t[i];
    }



    while (!q.empty()) {

        int cur = q.front();
        q.pop();

        for (int i = 0; i < g[cur].size(); i++) {

            indeg[g[cur][i]]--;
            res[g[cur][i]]=max(res[g[cur][i]], res[cur]+t[g[cur][i]]);

            if (!indeg[g[cur][i]]) {
                q.push(g[cur][i]);
            }
        }

    }

    for (int i = 1; i <= n; i++) {
        ans = max(ans, res[i]);
    }

    cout << ans;

    return 0;
}

1. 문제

n개의 작업이 걸리는 시간, 해당 작업 이전에 선행되어야 할 작업이 주어진다. 서로 선행 관계가 없는 작업은 동시에 수행이 가능하다. 작업 중에는 선행 관계가 없는 작업이 하나 이상 존재한다. 이 때, 모든 작업을 수행하는 데 걸리는 최소 시간을 구하라.

2. 풀이

선행 작업의 관계가 있으므로 위상 정렬을 이용하여 풀 수 있다. 

    for (int i = 1; i <= n; i++) {

        cin >> t[i];

        int inCnt;
        cin >> inCnt;

        for (int j = 0; j < inCnt; j++) {
            int temp;
            cin >> temp;
            g[temp].push_back(i);
            indeg[i]++;
        }
    }

각 작업에 걸리는 시간을 저장, 선행 작업이 먼저이므로 그래프에는 temp->i의 방향으로 저장, 선행작업의 개수 indeg를 세어준다.

 queue<int> q;
    res.resize(n + 1);

    for (int i = 1; i <= n; i++) {
        if (!indeg[i]) {
            q.push(i);
        }
        dp[i] = t[i];
    }

큐를 만들어 선행 관계가 없는 작업을 추가, dp 배열을 초기화해준다. dp[i]는 각 작업을 하는 데 걸리는 시간이다.

while (!q.empty()) {

        int cur = q.front();
        q.pop();

        for (int i = 0; i < g[cur].size(); i++) {

            indeg[g[cur][i]]--;
            dp[g[cur][i]]=max(dp[g[cur][i]], dp[cur]+t[g[cur][i]]);

            if (!indeg[g[cur][i]]) {
                q.push(g[cur][i]);
            }
        }

    }

큐에서 하나씩 빼주며 위상 정렬을 수행한다. 그리고 dp로 다음 작업을 수행하는 데 걸리는 시간을 갱신하는 데, 선행 작업을 모두 수행해야 하므로 선행 작업을 모두 하고 다음 작업을 하는 시간과 비교해준다.

    for (int i = 1; i <= n; i++) {
        ans = max(ans, res[i]);
    }

    cout << ans;

모든 작업이 끝나는 데 걸리는 시간을 출력해야 한다. 모든 시간 중 가장 늦게 끝나는 작업의 시간이 곧 모든 작업을 끝내는 데 걸리는 시간이므로 계산하여 출력해준다.

'Coding Test' 카테고리의 다른 글

백준 1806 부분합 (C++)  (2) 2024.08.04
백준 20924 트리의 기둥과 기지 (C++)  (0) 2024.08.02
백준 3107 IPv6 (C++)  (0) 2024.08.01
백준 16236 아기 상어 (C++)  (0) 2024.07.30
백준 1956 운동 (C++)  (0) 2024.07.29