시뮬레이션 (Simulation)
정의
시뮬레이션 (Simulation) 은 문제에서 제시한 규칙을 그대로 코드로 옮겨 한 단계씩 따라가는 알고리즘. 복잡한 로직보다 정확한 구현과 엣지 케이스 처리 가 핵심.
PS 에서 “~과정을 T 초 동안 반복한다”, “주어진 명령을 순서대로 실행한다” 같은 표현이 나오면 시뮬레이션.
문제 상황과 동기
보드 게임, 로봇 이동, 큐 처리, 달력, 시계 문제 등에서 과정 자체 를 모델링.
- naive: 규칙을 자연어로 이해만 하고 코드로 안 옮김 → WA.
- simulation (올바른 접근): 문제 조건을 하나하나
if-else/for/while로 번역. 테스트 케이스 손으로 따라가며 검증.
핵심 통찰: 문제가 묻는 대로 정확히 구현하면 정답. 알고리즘 최적화보다 버그 없는 코드 작성이 목표.
실전에서 “구현”, “시뮬레이션” 은 거의 동의어. 둘 다 문제 조건 1:1 대응.
시각화
핵심 아이디어
문제 지문의 절차 를 그대로 루프 / 조건문으로.
state = initial_state
for t = 1 to T:
state = apply_rule(state, t)
return state
invariant: 각 시점의 상태가 규칙에 부합. 중간 결과 출력 문제는 각 단계마다 검증.
대표 패턴:
- 시간 진행 (time evolution):
for t in 1..T. - 명령 처리 (command execution): 입력 명령을 큐나 배열로 받아 순차 실행.
- 보드 조작 (grid manipulation): 2D 배열 + 방향 벡터
dx, dy. - 객체 이동 (object movement): 위치, 방향, 속도 추적.
- 상태 전이 (state machine): 현재 상태 + 입력 → 다음 상태.
알고리즘
단순 시뮬레이션 (보드 게임)
grid = initial_grid
for command in commands:
if command == "U":
move_up(grid)
elif command == "D":
move_down(grid)
...
print(grid)
큐 처리
queue = [1, 2, 3, ...]
time = 0
while queue is not empty:
task = queue.pop_front()
time += task.duration
process(task)
구현
// 로봇이 N×N 보드를 상하좌우 이동. 명령 실행 후 위치 출력
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, x = 0, y = 0;
string commands;
cin >> n >> commands;
map<char, pair<int,int>> dir = {
{'U', {-1, 0}}, {'D', {1, 0}},
{'L', {0, -1}}, {'R', {0, 1}}
};
for (char c : commands) {
int nx = x + dir[c].first;
int ny = y + dir[c].second;
if (nx >= 0 && nx < n && ny >= 0 && ny < n) {
x = nx; y = ny;
}
}
cout << x << " " << y << "\n";
}5
RRDD2 2복잡도
| 항목 | 값 |
|---|---|
| 시간 | O(T · S) |
| 공간 | O(상태 크기) |
| 안정성 | - |
T = 시뮬레이션 단계 수, S = 한 단계 처리 비용. 보드 전체 순회면 S=O(N^2), 단순 이동이면 S=O(1).
실전 팁
1. 방향 벡터 (dx, dy)
int dx[4] = {-1, 1, 0, 0}; // 상하좌우
int dy[4] = {0, 0, -1, 1};
for (int d = 0; d < 4; d++) {
int nx = x + dx[d];
int ny = y + dy[d];
if (in_range(nx, ny)) { /* ... */ }
}
8방향이면 배열 크기 8.
2. 상태 복사 vs 인플레이스 갱신
격자가 동시 갱신이면 next_grid = copy(grid) 필요. 순차 갱신이면 인플레이스.
3. 디버그 출력
각 단계 후 print(state) 추가. 손 계산과 비교.
4. 테스트 케이스 자체 작성
문제 예제만으로 부족할 때, 극단 케이스 (빈 보드, 최대 크기, 모든 명령 같은 방향) 직접 만들어 검증.
변형
1. 시간 가속 (Time Skipping)
T=10^9 인데 실제 변화는 N 회뿐이면, 변화 시점만 큐/배열로 모아서 O(N).
events = [(t1, change1), (t2, change2), ...]
sort(events)
for (t, change) in events:
apply(change)
2. 주기 탐지 (Cycle Detection)
상태가 반복되면 나머지 연산으로 건너뛰기. 해시맵으로 state -> first_seen_time.
map<State, int> seen;
int cycle_start = -1, cycle_len = 0;
for (int t = 0; t < T; t++) {
if (seen.count(state)) {
cycle_start = seen[state];
cycle_len = t - cycle_start;
break;
}
seen[state] = t;
state = next(state);
}
if (cycle_len > 0) {
int remaining = (T - cycle_start) % cycle_len;
// cycle_start 에서 remaining 단계 더 진행
}
3. 너비 우선 탐색 결합
이동 가능한 모든 위치를 BFS 로 탐색하며 시뮬레이션.
함정
1. 인덱스 1-indexed vs 0-indexed
문제가 “1행 1열” 이라면 입력도 1-indexed. 배열은 0-indexed. 변환 주의.
2. 경계 검사 누락
if (nx >= 0 && nx < N && ny >= 0 && ny < N) 빠뜨리면 segfault / 이상한 출력.
3. 명령 순서 바뀜
입력 순서 그대로 실행해야 하는데, 정렬하거나 역순으로 처리 → WA.
4. 동시 갱신 vs 순차 갱신
“모든 칸이 동시에 다음 상태로” 면 임시 배열 필요. “왼쪽부터 순서대로” 면 인플레이스. 문제 지문 정확히 읽기.
5. 시간 초과 (TLE)
T=10^9 를 단순 루프로 → 주기 탐지 또는 시간 가속 필요.
BOJ 연습 문제
| 번호 | 제목 | 정답률 | 링크 |
|---|---|---|---|
| BOJ 14503 | 로봇 청소기 | 44.2% | kokoa-lab |
| BOJ 14891 | 톱니바퀴 | 48.5% | kokoa-lab |
| BOJ 15683 | 감시 | 42.1% | kokoa-lab |
| BOJ 3190 | 뱀 | 37.8% | kokoa-lab |
| BOJ 14499 | 주사위 굴리기 | 48.9% | kokoa-lab |
참고
이 글의 용어 (3개)
- [AWS] Step Functions: 워크플로 오케스트레이션cloud
- 정의 Step Functions = 서버리스 워크플로 오케스트레이션. Amazon States Language (ASL, JSON) 으로 상태 기계 정의. ASL 예시 시각화 자…
- 구현 (Implementation)algorithm
- 정의 구현 (Implementation) 은 PS 에서 알고리즘적 난이도는 낮지만 정확한 코딩이 필요한 문제 유형. 주로 시뮬레이션 (simulation), 조건 분기 (cond…
- 너비 우선 탐색 (BFS)algorithm
- 정의 너비 우선 탐색 (Breadth-First Search, BFS) 는 그래프 G=(V, E) 에서 시작 정점 s 로부터 가까운 정점부터 순서대로 방문하는 알고리즘. 큐 (F…
💬 댓글