본문 바로가기

알고리즘/백준

백준 2056 작업 - 위상정렬과 dp가 함께 쓰이는 문제

728x90

문제 링크

www.acmicpc.net/problem/2056

 

2056번: 작업

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

www.acmicpc.net

풀이 아이디어

작업을 완료하기 위해 어떤 작업이 먼저 수행되어야 하는지를 파악해야 하므로 

당연히 위상정렬 문제이다.

친절하게 각 줄의 두번째 int 값으로 indegree(먼저 수행되어야 하는 노드, 즉 조상노드의 개수)가 써져 있으므로

그대로 써먹으면 된다. (numOfancestor)

 

dp는 바로 이 '선행되는 조상노드의 실행 시간의 최댓값' 을 파악하기 위해 사용된다.

쉽게 예를 들어보겠다.

a라는 작업이 5분

b라는 작업이 10분

c라는 작업이 7분이 걸린다고 해보자.

이때 a는 반드시 b,c 작업이 끝나야 작업이 가능하다는 조건이 붙었다고 해보면

a를 끝낼 수 있는 최단 시간은 15분이다.

왜냐하면 b,c 중에서 더 작업 시간이 긴 b의 작업시간이 10분이기 때문이다.

(문제의 조건에 의해 b,c는 서로 연관이 없으므로 동시 수행이 가능)

코드에 해당하는 부분은 dp[next] = max(dp[next],dp[now]+t[next]); 이다.

next에 a가 들어가고 now 에 b,c가 들어가는 구조의 간단한 메모이제이션이다.

하지만 최댓값 기록을 위해,, 반드시 필요한 단계이다.

 

좋은 문제였다고 생각한다.

코드

#include <bits/stdc++.h>
using namespace std;

int n,answer;
int t[10001];
int dp[10001];
int numOfancestor[10001];
vector<int> A[10001];

int main(void){
    queue<int> q;
    cin>>n;
    for(int i=1; i<=n; i++){
        int x;
        cin>>t[i]>>x;
        dp[i]=t[i];
        numOfancestor[i]=x;
        if(x!=0){
            for(int j=0; j<x; j++){
                int pre;
                cin>>pre;
                A[pre].push_back(i);
            }
        }
    }
    for(int i=1; i<=n; i++)
        if(numOfancestor[i]==0)
            q.push(i);

    while(!q.empty()){
        int now = q.front();
        cout<<now<<" ";
        q.pop();
        for(int i=0; i<A[now].size(); i++){
            int next = A[now][i];
            dp[next] = max(dp[next],dp[now]+t[next]);
            numOfancestor[next]--;
            if(numOfancestor[next]==0)
                q.push(next);
        }
    }
    for(int i=1; i<=n; i++)
        answer = max(answer,dp[i]);
    cout<<answer;
}