본문 바로가기

알고리즘

6359번 : 만취한 상범

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

 

6359번: 만취한 상범

문제 서강대학교 곤자가 기숙사의 지하에는 n개의 방이 일렬로 늘어선 감옥이 있다. 각 방에는 벌점을 많이 받은 학생이 구금되어있다. 그러던 어느 날, 감옥 간수인 상범이는 지루한 나머지 정신나간 게임을 하기로 결정했다. 게임의 첫 번째 라운드에서 상범이는 위스키를 한 잔 들이키고, 달려가며 감옥을 한 개씩 모두 연다. 그 다음 라운드에서는 2, 4, 6, ... 번 방을 다시 잠그고, 세 번째 라운드에서는 3, 6, 9, ... 번 방이 열려있으면 잠그고

www.acmicpc.net

 

 

이 문제도 DP를 잘 정의하면 쉽게 풀 수 있다.

 

 

동적 계획법에서 항상 메모이제이션이 필요한 것은 아니다.

 

 


 

 

자, DP를 만약에 현재 라운드에서 탈출할 수 있는 사람의 수로 정의할 수 있을까?

 

 

 

R= 현재라운드

 

 

 

DP[R], DP[R - 1] 관계식을 세울 수 없다.

 

 


따라서, 뭔가 변수가 더 필요하다고 판단했다.

 

 

 

B = 방 번호

 

 

 

DP[B][R] = 방 번호가 B인 방에서, R 라운드에 문 열림의 유무

 

 

 

이렇게 되면, 재귀적으로 구성할 수 있다.

 

 

 

1) B가 R로 나누어 떨어질 때

- 이전 라운드에서 방문이 열려있다면, 닫기

- 이전 라운드에서 방문이 닫혀있다면 열기

 

 

2) B가 R로 나누어 떨어지지 않을 때

- 이전 라운드 방문을 그대로 나두기

 

 

 

자, 하향식 접근으로 문제를 풀었다. 상향식으로 풀면 더 쉬울 거 같긴하다.

 

 

 


 

 

해설코드(C++).

 

 

 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
#include <iostream>
#include <algorithm>
#include <cstring>
 
using namespace std;
 
int solve(int round, int Room) {
    if (round == 1)
        return 0;
 
    if (Room % round == 0) {
        if (solve(round - 1, Room) == 1) {
            return 0;
        }
        else {
            return 1;
        }
    }
    else {
        return solve(round - 1, Room);
    } 
}
 
int T, N;
 
int main(void) {
    freopen("input.txt""r", stdin);
    cin >> T;
    for (int i = 0; i < T; i++) {
        cin >> N;
        int result = 0;
        for (int i = 1; i <= N; i++)
            result += solve(N, i);
 
        cout << N - result << endl;
    }
    return 0;
}
http://colorscripter.com/info#e" target="_blank" style="color:#e5e5e5text-decoration:none">Colored by Color Scripter