본문 바로가기

백준일기장

(골드 3, c++) 백준 1516: 게임개발

 

 문제 

숌 회사에서 이번에 새로운 전략 시뮬레이션 게임 세준 크래프트를 개발하기로 하였다. 핵심적인 부분은 개발이 끝난 상태고, 종족별 균형과 전체 게임 시간 등을 조절하는 부분만 남아 있었다.

게임 플레이에 들어가는 시간은 상황에 따라 다를 수 있기 때문에, 모든 건물을 짓는데 걸리는 최소의 시간을 이용하여 근사하기로 하였다. 물론, 어떤 건물을 짓기 위해서 다른 건물을 먼저 지어야 할 수도 있기 때문에 문제가 단순하지만은 않을 수도 있다. 예를 들면 스타크래프트에서 벙커를 짓기 위해서는 배럭을 먼저 지어야 하기 때문에, 배럭을 먼저 지은 뒤 벙커를 지어야 한다. 여러 개의 건물을 동시에 지을 수 있다.

편의상 자원은 무한히 많이 가지고 있고, 건물을 짓는 명령을 내리기까지는 시간이 걸리지 않는다고 가정하자.

입력

첫째 줄에 건물의 종류 수 N(1 ≤ N ≤ 500)이 주어진다. 다음 N개의 줄에는 각 건물을 짓는데 걸리는 시간과 그 건물을 짓기 위해 먼저 지어져야 하는 건물들의 번호가 주어진다. 건물의 번호는 1부터 N까지로 하고, 각 줄은 -1로 끝난다고 하자. 각 건물을 짓는데 걸리는 시간은 100,000보다 작거나 같은 자연수이다. 모든 건물을 짓는 것이 가능한 입력만 주어진다.

출력

N개의 각 건물이 완성되기까지 걸리는 최소 시간을 출력한다.


핵심

 

  • 노드 개수 N (1 ≤ N ≤ 500)이 주어진다.
  • 각 노드마다:
    • 수행 시간 t
    • 수행 전에 완료되어야 하는 다른 노드 번호 목록이 주어진다. (입력은 -1로 끝남)
  • 여러 노드는 동시에 시작할 수 있다 (선행 제약만 지키면 됨).
  • 각 노드의 최소 완료 시간을 출력하라.

내가 작성한 코드

#include <iostream>
#include <queue>
#include <vector>
#include <algorithm>
using namespace std;

typedef pair<int, int> pii;
int indegree[501];

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

    int n;
    cin >> n;

    int time[n + 1];
    vector<int> edge[n + 1];
    for (int i = 1; i <= n; i++)
    {
        cin >> time[i];

        int temp;
        cin >> temp;

        while (temp != -1)
        {
            edge[temp].push_back(i);
            indegree[i]++;
            cin >> temp;
        }
    }

    priority_queue<pii, vector<pii>, greater<pii>> q;
    for (int i = 1; i <= n; i++)
    {
        if (!indegree[i])
        {
            q.push({time[i], i});
        }
    }

    int result[n + 1];
    while (!q.empty())
    {
        int size = q.size();

        for (int i = 0; i < n; i++)
        {
            auto [t, cur] = q.top();
            q.pop();

            result[cur] = t;

            for (auto ele : edge[cur])
            {
                indegree[ele]--;
                if (!indegree[ele])
                {
                    q.push({time[ele] + result[cur], ele});
                }
            }
        }
    }

    for (int i = 1; i <= n; i++)
    {
        cout << result[i] << "\n";
    }

    return 0;
}

 


풀이

이번 문제는 DP와 위상정렬 알고리즘을 사용하면 풀 수 있는 문제이다.

난이도가 골드 3인만큼 나에게는 조금 생각할 거리가 있는 문제였다.

 

https://qktjwl123.tistory.com/144

 

알고리즘: 위상정렬 (Kahn's Algorithm)

위상 정렬이란?방향 비순환 그래프(DAG)에서 정점들의 순서를 나열하는 알고리즘이다.이는 어떤 작업을 수행할 순서를 결정할 때 사용된다.간선 (A → B)는 "A를 먼저 하고, 그다음 B를 해라"라는

qktjwl123.tistory.com

해당 알고리즘을 이용하여 위상정렬 풀이를 진행해 업무가 끝나는 순을 계산하였고, 

시간을 계산할 때는 최소힙을 사용해 업무를 끝나는 시간 순으로 정렬해 준 뒤,

선행 업무의 끝나는 시간을 해당 업무 시간에 더해주어 계산하였다. (DP)

 

최소힙을 사용하지 않고 max() 함수를 통해서 이를 구현할 수도 있다.

더보기
더보기
#include <iostream>
#include <queue>
#include <vector>
#include <set>
#include <unordered_set>
#include <map>
#include <stack>
#include <unordered_map>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <sstream>
using namespace std;

typedef pair<int, int> pii;
int indegree[501];
int _time[501];
int result[501];
vector<int> edge[501];

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

    int n;
    cin >> n;

    for (int i = 1; i <= n; i++)
    {
        cin >> _time[i];

        int temp;
        cin >> temp;

        while (temp != -1)
        {
            edge[temp].push_back(i);
            indegree[i]++;
            cin >> temp;
        }
    }

    queue<int> q;
    for (int i = 1; i <= n; i++)
    {
        if (!indegree[i])
        {
            q.push(i);
            result[i] = _time[i];
        }
    }

    while (!q.empty())
    {
        int size = q.size();

        for (int i = 0; i < n; i++)
        {
            int cur = q.front();
            q.pop();

            for (auto ele : edge[cur])
            {
                indegree[ele]--;
                result[ele] = max(result[cur] + _time[ele], result[ele]);
                if (!indegree[ele])
                {
                    q.push(ele);
                }
            }
        }
    }

    for (int i = 1; i <= n; i++)
    {
        cout << result[i] << "\n";
    }

    return 0;
}

 

for문 내에서 이후 업무의 끝나는 시간을 max()로 계산한다.

 


시간 복잡도

위상정렬와 같은 시간 복잡도를 갖는다. O(V+E).