# 문제
탁자 위에 돌 N개가 있다. 상근이와 창영이는 턴을 번갈아가면서 돌을 가져가며, 돌은 1개 또는 3개 가져갈 수 있다. 마지막 돌을 가져가는 사람이 게임을 이기게 된다. 두 사람이 완벽하게 게임을 했을 때, 이기는 사람을 구하는 프로그램을 작성하시오. 게임은 상근이가 먼저 시작한다.
# 풀이1
간만에 돌아온 알고리즘 풀이
해당 문제는 아주 간단하게 풀 수도 있지만 다이나믹 프로그래밍 DP로도 풀어볼 수 있다. 약간 DP 맛보기 문제랄까?
우선 아주 간단하게 푸는 방법 먼저 확인해보자.
#include <iostream>
using namespace std;
int main(){
int n;
cin >> n;
if(n%2 == 0) cout << "CY";
else cout << "SK";
return 0;
}
정말 간단하다! 몇 개의 입력 n을 가정해두고 누가 이기는지 직접 적어보자.
n | 게임 | 승자 |
1 | 상근(1) | SK |
2 | 상근(1) - 창영(1) | CY |
3 | 1. 상근(3) 2. 상근(1) - 창영(1) - 상근(1) |
SK |
4 | 1. 상근(3) - 창영(1) 2. 상근(1) - 창영(3) 3. 상근(1) - 창영(1) - 상근(1) - 창영(1) |
CY |
5 | 1. 상근(3) - 창영(1) - 상근(1) 2. 상근(1) - 창영(1) - 상근(3) 3. 상근(1) - 창영(1) - 상근(1) - 창영(1) - 상근(1) |
SK |
직접 적어가며 몇 가지 입력을 확인하다보면, 게임이 어떻게 흘러가든 입력 n에 따른 승자는 항상 동일한 것을 확인할 수 있다.
따라서 우리는 입력 n과 승자의 관계를 알아내면 된다는 뜻!
이 문제는 아주 간단하게 해결되는데 입력 n이 홀수인 경우에는 항상 상근이가 승리하고,
입력 n이 짝수인 경우에는 항상 창영이가 승리한다.
코드로 짜는 것은 아주 간단하니 바로 DP를 활용해 푸는 방법을 알아보자.
# 풀이2
#include <iostream>
#include <algorithm>
using namespace std;
int main(){
int n;
cin >> n;
const int MAX = 1001;
int D[MAX]; // DP 테이블 생성 및 초기값 할당
D[1] = 1;
D[2] = 2;
D[3] = 1;
for(int i = 4; i <= n; i++){
D[i] = min(D[i-1] + 1, D[i-3] + 1);
}
if(D[n]%2 == 0) cout << "CY";
else cout << "SK";
return 0;
}
DP로 문제를 풀 땐 해당 문제가 작은 문제들로 나누어지는지, 그 작은 문제들이 반복되어 나타나고/사용되고 있는지를 먼저 확인해야 한다.
현재 풀고 있는 문제에서는 1 과 3중 어떤 것을 선택하는지의 문제로 나누어지고, 이것을 활용해 승리까지 몇 턴이 도는가를 DP 테이블에 저장해 반복적으로 활용하면 원하는 최종 정답을 구해낼 수 있다는 것을 기억하고 코드를 살펴보자.
const int MAX = 1001;
int D[MAX]; // DP 테이블 생성 및 초기값 할당
D[1] = 1;
D[2] = 2;
D[3] = 1;
입력 N의 범위가 1 ≤ N ≤ 1000 이므로 최대 1001의 값을 갖는 DP 테이블을 생성해주었다. (여기선 배열의 형태지만 편의상 DP 테이블로 언급) 그리고 간단하게 구할 수 있는, 작은 문제들을 해결해 초기값으로 할당해준다. 이때 턴이 최소한으로 돌아가는 것을 문제에서 언급한 완벽한 게임이라고 가정하였다. (따라서 D[3] = 1)
이제 작은 문제들로 큰 문제를 해결해보자.
입력이 4인 경우 우리는 1, 혹은 3을 선택할 수 있다.
따라서 D[3]에서 1을 선택하는 턴을 하나 더해주고, D[1]에서 3을 선택하는 턴을 하나 더해주는 두 개의 선택지가 존재한다.
또한 완벽한 게임을 가정했으므로 두 가지 선택지 중 더 적은 턴을 사용하는 것을 D[4]로 정의해줄 수 있다.
for(int i = 4; i <= n; i++){
D[i] = min(D[i-1] + 1, D[i-3] + 1);
}
위에서 말로 풀어 확인해본 과정을 일반화해보면 위와 같은 코드를 얻을 수 있고,
해당 과정을 통해 구해준 최소한의 D[i]로 홀수, 짝수를 따지면(첫번째 풀이와 동일하게) 누가 승리했는지 찾을 수 있다.
9655번: 돌 게임
상근이가 게임을 이기면 SK를, 창영이가 게임을 이기면 CY을 출력한다.
www.acmicpc.net
'백준 > C++' 카테고리의 다른 글
[백준] 1932번: 정수 삼각형 | C++ 풀이 (0) | 2023.11.11 |
---|---|
[백준] 2609번: 최대공약수와 최소공배수 | C++ 풀이 (0) | 2023.07.05 |
[백준] 2164번: 카드2 | C++ 풀이 (0) | 2023.07.04 |
[백준] 1259번: 팰린드롬수 | C++ 풀이 (0) | 2023.07.03 |
[백준] 1920번: 수 찾기 | C++ 풀이 (0) | 2023.07.02 |