본문 바로가기

Dot Algo∙ DS/PS

[BOJ] 백준 9657번 돌 게임3 (JAVA)

    #9657 돌 게임3

    난이도 : 실버 3

    유형 : DP/ 게임 이론

     

    9657번: 돌 게임 3

    상근이가 게임을 이기면 SK를, 창영이가 게임을 이기면 CY을 출력한다.

    www.acmicpc.net

    ▸ 문제

    돌 게임은 두 명이서 즐기는 재밌는 게임이다.

    탁자 위에 돌 N개가 있다. 상근이와 창영이는 턴을 번갈아가면서 돌을 가져가며, 돌은 1개, 3개 또는 4개 가져갈 수 있다. 마지막 돌을 가져가는 사람이 게임을 이기게 된다.

    두 사람이 완벽하게 게임을 했을 때, 이기는 사람을 구하는 프로그램을 작성하시오. 게임은 상근이가 먼저 시작한다.

     

     입력

    첫째 줄에 N이 주어진다. (1 ≤ N ≤ 1000)

     

     출력

    상근이가 게임을 이기면 SK를, 창영이가 게임을 이기면 CY을 출력한다.

     

     

     

    문제 풀이 

    돌맹이 n개를 1,3,4개를 가져갈 수 있고 마지막으로 가져간 사람이 이기는 게임이다. 처음에는 단순하게 규칙을 찾아 풀었지만 dp로 분류된 문제이니 dp로도 풀어야겠다 싶어서 다시 풀었다. 

     

    규칙 찾기 문제로, 경우의 수를 몇 번 계산해보면 금방 규칙을 찾을 수 있다.

    상근이는 7을 주기로 패/승/패/승/승/승/승 의 경우의 수가 나온다.

     

    DP 풀이

    상근이를 기준으로 dp[i] = 1 이면 상근이 이긴다고 설정했다.

     

    돌이 1개, 3개, 4개가 있으면 무조건 상근이가 승리하고 2개일 경우 조합이 (1,1)밖에 안되기 때문에 무조건 상근이가 패배한다.

     

    그래서 초기값은 다음과 같다.

    dp[1] = 1, dp[2] = 0, dp[3] = 1, dp[4] = 1

     

    위의 초기값을 토대로 점화식을 설계하면 된다. 이 게임은 상근이가 먼저 시작하므로 주도권은 상근이한테 있다.

     

    예) 6개의 돌로 시작하는경우

    1  -> dp[5] = 1 (dp[5]는 dp[4], dp[2], dp[1] 중 이기는 경우 1개라도 존재하므로 1)

    3  -> dp[3] = 1

    4  -> dp[2] = 0

    ☛ 상근이가 먼저 뽑아서 두 번째로 뽑는 창영이가 지는 경우의 수가 존재하면 무조건 상근이가 그걸 계산해서 이긴다고 보면 된다.

    (4개를 잡으면 상근이 승리 4(SK)-> 1 (CY)-> 1(SK) )

     

    그럼 반대로 무조건 상근이가 지는 경우는 언제일까?

     

    예) 7개의 돌로 시작하는 경우

    1  -> dp[6] = 1

    3  -> dp[4] = 1

    4  -> dp[3] = 1

     

    ☛ 다음과 같이 상근이가 먼저 뽑은 다음 두 번째로 뽑는 창영이가 지는 경우의 수가 없을 때이다. 위의 경우랑은 역으로 무엇을 뽑든 지는 경우가 있다. 

     

    그래서 dp[i-1] + dp[i-3] + dp[i-4] == 3이면, 다음에 상근이는 무조건 지기때문에 dp[i]=0으로 값을 주고

    나머지는 다 1로 이기는 경우의 수가 존재하기 때문에 이런식으로 메모이제이션을 해나가면 된다.

     

     

    풀이 코드 

    import java.util.Scanner;
    
    public class Main {
    
    	public static void main(String[] args) {
    		Scanner sc = new Scanner(System.in);
    		
    		int n = sc.nextInt();
    		
    		// if 1 : SK win
    		//    0 : CY win  
    		int[] dp = new int[n+1];
    		dp[1] =1;
    		dp[2] =0;
    		dp[3] =1;
    		dp[4] =1;
    		
    		for(int i=5; i<n+1; i++) {
    			// 1,3,4 == 합 3이면 뭐를 넣어도 다음 사람이 이김 
    			if(dp[i-1] + dp[i-3] + dp[i-4] <3) {
    				dp[i] =1;
    			}else {
    				dp[i] =0;
    			}
    		}
    		
    		if(dp[n] ==1) {
    			System.out.println("SK");
    		}else {
    			System.out.println("CY");
    		}
    		
    		
    		
    //		규칙 풀이 
    //		int d = n%7;
    //		
    //		System.out.println(d);
    //		
    //		switch(d) {
    //			case 0: case 2:
    //				System.out.println("CY");
    //				break;
    //			default:
    //				System.out.println("SK");
    //				break;
    //		}
    	}
    	
    }