[백준 17825번 C/C++] 주사위 윷놀이

 

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

 

17825번: 주사위 윷놀이

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

www.acmicpc.net


 

 

해결전략

 

백트래킹 Backtracking

 

 

이 문제는 풀지 못하고 다른 사람의 풀이를 보았다.

백트래킹 문제인건 인지하였지만 문제 조건을 세팅하는게 힘들었다. 주어진 숫자들을 다소 하드코딩하여 배열로 세팅하는 과정이 필요하였다. 아래와 같이 6개의 배열을 준비하여 사용한다. 이 부분이 생각하기 힘들었다.  

 

  • vector<int> dice(10);     // 주사위 눈금
  • vector<int> player(4);    // 4개의 말이 위치한 칸의 번호

  • vector<int> location(34); // 각 칸에서 다음 칸으로 이동할 때의 인덱스
  • vector<int> score(34);    // 각 칸의 점수
  • vector<int> turn(34);     // 파란색 화살표가 있는 칸에서 다른 경로로 바꿀 인덱스
  • vector<bool> bPresent(34, false); // 각 칸에 말이 존재하는지 여부

 


 

 

정답코드

 

#include <iostream>
#include <vector>
#include <cmath>
using namespace std;

int answer;                     // 최대 점수를 저장할 변수
vector<int> dice(10);     // 주사위 눈금
vector<int> player(4);    // 4개의 말이 위치한 칸의 번호

vector<int> location(34); // 각 칸에서 다음 칸으로 이동할 때의 인덱스
vector<int> score(34);    // 각 칸의 점수
vector<int> turn(34);     // 파란색 화살표가 있는 칸에서 다른 경로로 바꿀 인덱스
vector<bool> bPresent(34, false); // 각 칸에 말이 존재하는지 여부

void BackT(int cnt, int sum)
{
    if (cnt == 10) { // 주사위를 모두 사용했을 때
        answer = max(answer, sum); // 최대 점수 갱신
        return;
    }

    for (int i = 0; i < 4; i++) // 4개의 말에 대해 반복
    {
        int prev = player[i]; // 현재 말의 위치
        int cur = prev;
        int move = dice[cnt]; // 이번에 이동할 주사위 눈금

        if (turn[cur] > 0) { // 현재 위치가 파란색 화살표 지점이라면
            cur = turn[cur]; // 경로 전환
            move--;          // 이동 횟수 1 감소
        }

        while (move--) { // 남은 이동횟수만큼 이동
            cur = location[cur];
        }

        if (cur != 21 && bPresent[cur]) continue; // 도착 칸이 아니고, 이미 다른 말이 있는 칸이라면 이동 불가

        bPresent[prev] = false; // 이전 위치를 비움
        bPresent[cur] = true;   // 현재 위치에 말을 놓음
        player[i] = cur;        // 말의 위치 갱신

        BackT(cnt + 1, sum + score[cur]); // 재귀 호출로 다음 주사위 눈금 처리

        // 백트래킹을 위해 상태 복원 (4개의 말에 대해 반복해야 하니 복원함)
        player[i] = prev;
        bPresent[prev] = true;
        bPresent[cur] = false;
    }
}

void GivenInfo()
{
    // 윷놀이 판의 기본 구성 설정
    for (int i = 0; i < 27; i++) {
        location[i] = i + 1;
    }
    location[21] = 21; // 도착 칸 설정

    // 특수 경로 설정
    location[27] = 20; location[28] = 29; location[29] = 30;
    location[30] = 25; location[31] = 32; location[32] = 25;

    // 파란색 화살표가 있는 칸에서 다른 경로로 전환하는 설정
    turn[5] = 22; turn[10] = 31; turn[15] = 28;

    // 각 칸의 점수 설정
    for (int i = 0; i < 21; i++) {
        score[i] = 2 * i;
    }
    // 특수 경로의 점수 설정
	score[22] = 13; score[23] = 16; score[24] = 19;
	score[25] = 25; score[26] = 30; score[27] = 35;
	score[28] = 28; score[29] = 27; score[30] = 26;
	score[31] = 22; score[32] = 24;
}

int main(){
	ios::sync_with_stdio(false);
	cin.tie(0); cout.tie(0);

	GivenInfo();

	for (int i = 0; i < 10; i++){
		cin >> dice[i];
	}

	BackT(0, 0);

	cout << answer << "\n";
	return 0;
}

 


 

 

 

풀이를 참고한 곳

 

https://bloofer.net/65

 

[백준 17825] 주사위 윷놀이 (C++)

 

bloofer.net