백준온라인

[백준온라인] 17825번 주사위 윷놀이

cbkpar 2019. 12. 22. 01:06

문제 : https://www.acmicpc.net/problem/17825

 

17825번: 주사위 윷놀이

첫째 줄에 주사위에서 나올 수 10개가 순서대로 주어진다.

www.acmicpc.net

문제 요약 : 주사위를 10번 돌려 얻을 수 있는 점수의 최댓값 출력

입력 출력

1 ≤ (주사위 10개) ≤ 5

주사위를 10번 돌려 얻을 수 있는 점수의 최댓값 출력

 

JAVA

채점 번호 아이디 문제 번호 결과 메모리 시간 언어 코드 길이
16546976 cbkpar 17825 맞았습니다!! 14496KB 84ms Java 2838B
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.OutputStreamWriter;
import java.util.StringTokenizer;

public class Main {
	
    //현재위치에서 주사위를 굴렸을때 이동할 위치 미리 정해둠
	static int[][] map = {{0,1,2,3,4,5},
			{1,2,3,4,5,6},
			{2,3,4,5,6,7},
			{3,4,5,6,7,8},
			{4,5,6,7,8,9},
			{5,21,22,23,29,30},
			{6,7,8,9,10,11},
			{7,8,9,10,11,12},
			{8,9,10,11,12,13},
			{9,10,11,12,13,14},
			{10,27,28,29,30,31},
			{11,12,13,14,15,16},
			{12,13,14,15,16,17},
			{13,14,15,16,17,18},
			{14,15,16,17,18,19},
			{15,24,25,26,29,30},
			{16,17,18,19,20,32},
			{17,18,19,20,32,32},
			{18,19,20,32,32,32},
			{19,20,32,32,32,32},
			{20,32,32,32,32,32},
			{21,22,23,29,30,31},
			{22,23,29,30,31,20},
			{23,29,30,31,20,32},
			{24,25,26,29,30,31},
			{25,26,29,30,31,20},
			{26,29,30,31,20,32},
			{27,28,29,30,31,20},
			{28,29,30,31,20,32},
			{29,30,31,20,32,32},
			{30,31,20,32,32,32},
			{31,20,32,32,32,32},
			{32,32,32,32,32,32}};
    //정해둔 위치에 도착했을 때 더할 점수
	static int[] score = {0,2,4,6,8,10,12,14,16,18,20,22,24,26,28,30,32,
			34,36,38,40,13,16,19,28,27,26,22,24,25,30,35,0};
	static int a=0;
	static int b=0;
	static int c=0;
	static int d=0;
	static int m=0;
	static int[] chk = new int[33];
	static int[] move = new int[10];
	
	public static void main(String args[]) throws IOException {
		BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
		BufferedWriter bw = new BufferedWriter(new OutputStreamWriter(System.out));
		int i;
		StringTokenizer st = new StringTokenizer(br.readLine());
		for(i=0;i<10;i++) move[i]=Integer.parseInt(st.nextToken());
		chk[32]=-10;
		if(move[0]==move[1]) {
        //첫번째와 두번째 이동이 같다면 처음에 이동한말이 한번더 이동해야하는 사실은 자명하다.
			chk[map[move[0]][move[0]]]++;
			a=map[move[0]][move[0]];
			dfs(score[move[0]]+score[a],2);
		}else {
        //첫번째와 두번째 이동이 다르다면 처음이동한말이 이동하거나 새로운말이 이동하는 경우 2가지이다.
			chk[move[0]]++;
			chk[move[1]]++;
			a=move[0];
			b=move[1];
			dfs(score[a]+score[b],2);
			chk[move[0]]--;
			chk[move[1]]--;
			chk[map[move[0]][move[1]]]++;
			a=map[move[0]][move[1]];
			b=0;
			dfs(score[move[0]]+score[map[move[0]][move[1]]],2);
		}
		bw.write(m+"\n");
		br.close();
		bw.close();
	}
	
	static void dfs(int sum, int k) {
		if(k==10) {
        //10번 다 돌렸을 경우 최댓값 갱신 후 리턴
			m = Math.max(m, sum);
			return;
		}
		int tmp,tmp2;
		tmp = map[a][move[k]];
		if(chk[tmp]!=1) { // 이동가능 여부 파악
			chk[tmp]++; // 이동한 위치 말 추가
			chk[a]--; // 현재 위치 말 제거
			tmp2=a;
			a=tmp;
			dfs(sum+score[tmp],k+1); // 점수를 더하고 재귀
			a=tmp2;
			chk[a]++; // 현재 위치 말 추가
			chk[tmp]--; //이동한 위치 말 제거
		}
		tmp = map[b][move[k]];
		if(chk[tmp]!=1) {
			chk[tmp]++;
			chk[b]--;
			tmp2=b;
			b=tmp;
			dfs(sum+score[tmp],k+1);
			b=tmp2;
			chk[b]++;
			chk[tmp]--;
		}
		tmp = map[c][move[k]];
		if(chk[tmp]!=1) {
			chk[tmp]++;
			chk[c]--;
			tmp2=c;
			c=tmp;
			dfs(sum+score[tmp],k+1);
			c=tmp2;
			chk[c]++;
			chk[tmp]--;
		}
		tmp = map[d][move[k]];
		if(chk[tmp]!=1) {
			chk[tmp]++;
			chk[d]--;
			tmp2=d;
			d=tmp;
			dfs(sum+score[tmp],k+1);
			d=tmp2;
			chk[d]++;
			chk[tmp]--;
		}
	}
}

위와 같은 방식을 사용하지않고 10번을 모두 dfs로 풀 수 있다.

이때 경우의수는 4^10 = 1048576 이게 되지만

 

첫번째 수는 어떤 말이 이동해도 결과는 같기때문에 첫번째 말이 이동했다고 가정하고 풀게되면

경우의수는 4^9로 262144번만 계산하면 된다.

 

또한 2번째 수 까지 고려했을때

첫번째 두번째 주사위가 같은 수 일경우 처음이동한 말이 또 이동해야 하며

첫번째 두번째 주사위가 다른 수 일경우 처음이동한말이 이동을 다시하거나 새로운말이 이동할경우로 나누어주면

 

총 3 * 65536 = 196608의 경우의수가 생기게 된다.