[백준] 게임 개발
문제 링크: https://www.acmicpc.net/problem/1516
오랜만에 위상정렬 개념을 생각해보니 떠오르지 않아서 기본적인 위상정렬 문제를 가져왔다.
- 위상정렬(Topology Sort)이란?
순서가 정해져있는 작업을 차례로 수행해야할 때 그 순서를 결정해주기 위해 사용하는 알고리즘이다.
방법
- 진입차수가 0인 정점을 큐에 삽입한다.
- 큐에서 원소를 꺼내 연결된 모든 간선을 제거한다.
- 간선 제거 이후에 진입차수가 0이된 정점을 큐에 삽입한다.
- 큐가 빌 대까지 2번과 3번 과정을 반복한다. 모든 원소를 방문하기 전에 큐가 빈다면 사이클이 존재하는 것이고, 모든 원소를 방문했다면 큐에서 꺼낸 순서가 위상정렬의 결과이다.
위 문제에서는 순서를 정하라고 직접적인 힌트는 없지만, 건물을 짓는 데 선후 관계가 있음을 알려서 순서가 있음을 내포한다.
#include <iostream>
#include <vector>
#include <queue>
#include <algorithm>
using namespace std;
// parent -> child
vector <int> graph[501];
queue <int> q;
int times[501];
// priors : i번째 건물을 짓는 데 필요한 건물의 수
int priors[501] = {0};
int result[501] = {0};
int n;
int main(void){
int t, prior;
cin >> n;
for(int i = 1;i <= n;i++) {
cin >> t;
times[i] = t;
while(1){
cin >> prior;
if(prior == -1) break;
// 건물 하나 짓는데 그 이전에 지어야하는 건물이 여러 개일 가능성 존재
priors[i]++;
graph[prior].push_back(i);
}
}
// 진입차수가 0인 노드를 큐에 우선 삽입
for(int i = 1;i <= n;i++){
if(priors[i] == 0){
result[i] = times[i];
q.push(i);
}
}
// 위상 정렬이 완전히 수행되려면 n개의 노드 pop
// 만약 큐가 먼저 empty되면 cycle이 있는 것이다.
for(int i = 1;i <= n;i++){
if(!q.empty()){
int x = q.front();
q.pop();
for(int j = 0;j < graph[x].size();j++){
int y = graph[x][j];
result[y] = max(result[y], result[x] + times[y]);
if(--priors[y] == 0){
q.push(y);
}
}
}
}
for(int i = 1;i <= n;i++){
cout << result[i] << endl;
}
}
위 위상정렬의 개념을 적용하여 이 문제를 접근하면 건물별로 짓는 데 필요한 time, 먼저 지어져야 하는 건물 개수 prior을 입력받는다.
그리고 역으로 건물 간의 선후 관계를 linked list의 형태로 저장한다.
그 중 기존과 달리 vector<vector<int>>의 형태로 하면 에러가 발생한다. 왜냐면 역으로 push_back할 때 아직 메모리도 생성되지 않은 vector의 push_back 메소드하는 격이 되기 때문이다.
그래서 이번엔 vector의 array 형식으로 접근하고자 한다.
e.g. vector<int> graph[501]
그래서 예제의 결과를 시각화하면 다음과 같다.
(이미지처리하기 귀찮아)
아무래도 아직 위상정렬을 터득하지 못한 거 같아서 한 문제 더 풀고 자야겠다.
Author And Source
이 문제에 관하여([백준] 게임 개발), 우리는 이곳에서 더 많은 자료를 발견하고 링크를 클릭하여 보았다 https://velog.io/@dleunji/백준-게임-개발저자 귀속: 원작자 정보가 원작자 URL에 포함되어 있으며 저작권은 원작자 소유입니다.
우수한 개발자 콘텐츠 발견에 전념 (Collection and Share based on the CC Protocol.)