백준 12869 - 뮤탈리스크
Updated:
Java
12869 번 - 뮤탈리스크
문제
접근 방법
SCV 입력 받기
우선 문제의 조건에 scv는 최소 1마리 부터 3마리까지 들어 올 수 있다.
따라서 크기가 3인 int형 배열을 선언하여 받는다.
이는 SCV 1마리나 2마리를 받아도 남은 빈자리는 체력이 0이므로 죽은 것으로 간주하면 된다.
뮤탈리스크의 공격
뮤탈리스크는 총 3번을 공격하며, 각각 체력 9, 3, 1을 깎는다.
이를 순열로 나열하면 총 6가지가 나오는데, 각 경우마다 6가지의 공격을 하여 DFS를 통해 재귀로 모든 경우의 수를 탐색한다.
DP
위의 방법으로만 계산하면 시간 초과가 나올 것으로 예상된다.
따라서 3차원 DP를 두어, 각 SCV의 체력까지 도달하는데 걸리는 뮤탈리스크의 공격을 저장한다.
이후 이전과 똑같은 SCV 3개의 체력으로 새로운 함수를 호출 하였을 때, 이전의 공격 횟수보다 현재 도달하는데 걸린 횟수가 같거나 더 크다면 더 이상 탐색할 필요가 없으므로 종료하는 방식으로 Back-Tracking을 한다.
따라서, 문제의 핵심이 되는 코드는
if(dp[a][b][c] <= cnt && dp[a][b][c] != 0) {
return;
}
이다.
코드
import java.util.*;
import java.io.*;
public class Main {
static int n, result = Integer.MAX_VALUE;
static int[][][] dp;
public static void main(String[] args) throws IOException {
BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
n = stoi(br.readLine());
StringTokenizer stk = new StringTokenizer(br.readLine());
dp = new int[61][61][61];
int[] arr = new int[3];
for(int i = 0; i < n; i++) {
arr[i] = stoi(stk.nextToken());
}
DFS(arr,0);
System.out.println(result);
br.close();
}
static int[] arrA = {9,9,3,3,1,1};
static int[] arrB = {3,1,9,1,9,3};
static int[] arrC = {1,3,1,9,3,9};
static void DFS(int[] arr, int cnt) {
int a = arr[0];
int b = arr[1];
int c = arr[2];
// 한번 방문한 상태에서 현재 수 보다 dp로 저장한 수가 더 작은 경우
if(dp[a][b][c] <= cnt && dp[a][b][c] != 0) {
return;
}
// 종료 조건
if(a == 0 && b == 0 && c == 0) {
result = Math.min(result, cnt);
return;
}
dp[a][b][c] = cnt;
// 뮤탈리스크가 공격 할 수 있는 모든 경우의 수를 따진다.
int nA, nB, nC;
for(int i = 0; i < 6; i++) {
nA = a - arrA[i];
nB = b - arrB[i];
nC = c - arrC[i];
if(nA < 0) nA = 0;
if(nB < 0) nB = 0;
if(nC < 0) nC = 0;
DFS(new int[] {nA, nB, nC}, cnt + 1);
}
}
static int stoi(String str) {
return Integer.parseInt(str);
}
}
총평
후기
처음에 dp로 백트래킹을 할 때 한번 방문 했으면 바로 return하게 하였다.
이는 이후에 도달한 경우에서 더 단축 된 경우가 있을 수 있으므로 이전 DP와 현재 cnt를 비교하는 방법으로 백 트래킹을 수행하여야 한다.