Algorithm/back_tracking
[틀림] [알고리즘] 백준 17825 주사위윷놀이 // 완탐 , 구현, 인접리스트, 백트래킹
Mini_96
2025. 2. 15. 01:16
https://www.acmicpc.net/problem/17825
* 틀린풀이
- 그리디 (틀린풀이)
- 먼저 완탐이 되는지 봤어야함
- 인접리스트 사용안하고 vector 여러개로 구현하다보니 너무 복잡... gg

* 정답풀이


- adj로 2개 연결하는것도 표현
- 값은 v에, index는 adj에 저장 // 값과 index를 분리해서 저장하라.
- adj.size로 특수이동인지 판별
- 백트래킹으로 모든 경로 확인
#include<bits/stdc++.h>
using namespace std;
const int INF = 987654321;
// 게임에 필요한 전역 변수들
int a[14]; // 주사위 값을 저장하는 배열
int mal[4]; // 4개의 말의 현재 위치를 저장하는 배열
int n = 10; // 총 주사위 던지는 횟수
int v[104]; // 각 칸의 점수를 저장하는 배열, v[100] = 0점처리!!
vector<int> adj[54]; // 게임판의 연결 상태 (인접 리스트)
// 현재 위치(here)에서 주사위 값(cnt)만큼 이동했을 때의 도착 위치를 반환
int move(int here, int cnt){
if(here==100) return 100; //이미 도착점인경우, 100번 반환
//특수 위치인경우
if(adj[here].size()>=2) {
here = adj[here][1]; // 이동시켜
cnt--;
}
if(cnt<=0) return here; //특수위치이동후, 이동횟수없는경우 특수 이동시킨위치 리턴
//일반 이동인 경우
//인접리스트에서 cnt만큼 한칸씩 이동시킴
queue<int> q;
q.push(here);
int there;
while(q.size()) {
int x = q.front(); q.pop();
there = adj[x][0];
if(there == 100) break;
q.push(there);
cnt--; //이동횟수 감소!
if(cnt<=0) break;
}
return there;
}
// 말이 겹치는지 확인하는 함수(도착할위치, 나자신 )
bool isMal(int nxt, int idx){
if(nxt == 100) return false;
for(int i=0;i<4;++i) {
if(i==idx) continue; // 탐색대상에서 나 자신은 제외
if(mal[i] == nxt) return true; // 다른말의 위치 == 도착할위치인경우, 겹침
}
return false;
}
// 게임판에 간선 추가하는 함수
void add(int here, int there){
adj[here].push_back(there);
}
// 게임판 초기화 함수
void setMap(){
// 빨간색 화살표 경로 설정 (0~19)
for(int i = 0; i <= 19; i++) add(i, i + 1);
// 파란색 화살표 경로 설정
// 5번 칸에서 시작하는 경로
add(5, 21); add(21, 22); add(22, 23); add(23, 24);
// 15번 칸에서 시작하는 경로
add(15, 29); add(29, 30); add(30, 31); add(31, 24);
// 10번 칸에서 시작하는 경로
add(10, 27); add(27, 28); add(28, 24);
// 공통 경로
add(24, 25); add(25, 26); add(26, 20); add(20, 100);
// 각 칸의 점수 설정
v[1] = 2; v[2] = 4; v[3] = 6; v[4] = 8; v[5] = 10;
v[6] = 12; v[7] = 14; v[8] = 16; v[9] = 18; v[10] = 20;
v[11] = 22; v[12] = 24; v[13] = 26; v[14] = 28; v[15] = 30;
v[16] = 32; v[17] = 34; v[18] = 36; v[19] = 38; v[20] = 40;
v[21] = 13; v[22] = 16; v[23] = 19; v[24] = 25;
v[27] = 22; v[28] = 24; v[25] = 30; v[26] = 35;
v[29] = 28; v[30] = 27; v[31] = 26;
}
// DFS로 최대 점수를 찾는 함수
// depth : 트리의 depth, 주사위의 index
int go(int depth, int sum){
if(depth == n) return sum; // 모든 주사위를 다 던졌으면 종료
int ret = 0; // 현재 상태에서의 최대 점수
for(int i = 0; i < 4; i++){ // 4개의 말에 대해 시도
int tmp_idx = mal[i]; // 원복용 값저장
int nxt = move(mal[i], a[depth]); // 도착할 위치
if(isMal(nxt,i)) continue; // 도착할위치에 다른말이 있는경우
mal[i] = nxt; //말 이동
ret = max(ret, go(depth+1, sum+v[nxt]));
mal[i] = tmp_idx; //원복
}
return ret; // 최대 점수 반환
}
int main(){
ios_base::sync_with_stdio(false);
cin.tie(NULL); cout.tie(NULL);
setMap(); // 게임판 초기화
for(int i = 0; i < n; i++) cin >> a[i]; // 주사위 값 입력
cout << go(0,0) << "\n"; // 최대 점수 계산 및 출력
return 0;
}
- move에서 return값이 100인경우, v[100]이 0 -> 자동으로 0점처리되어 영향을 주지않고, 구현이 쉬워짐