소스코드
n = int(input())
scv = list(map(int, input().split()))
scv.extend([0, 0])
dp = [[[0]*61 for _ in range(61)] for _ in range(61)]
dp[scv[0]][scv[1]][scv[2]] = 1
comb = [(9, 3, 1), (9, 1, 3), (3, 9, 1), (3, 1, 9), (1, 9, 3), (1, 3, 9)]
for i in range(60, -1, -1):
for j in range(60, -1, -1):
for k in range(60, -1, -1):
if dp[i][j][k] > 0:
for c in comb:
i_ = i-c[0] if i-c[0] >= 0 else 0
j_ = j-c[1] if j-c[1] >= 0 else 0
k_ = k-c[2] if k-c[2] >= 0 else 0
if dp[i_][j_][k_] == 0 or dp[i_][j_][k_] > dp[i][j][k]+1:
dp[i_][j_][k_] = dp[i][j][k]+1
print(dp[0][0][0]-1)
알고리즘
예전에 푼 문제가 블로그에서 가장 높은 조회수를 달성했는데 그만큼의 퀄리티가 나오지 않아서 풀이를 다시 작성해봅니다.
- scv라는 리스트에 현재 체력을 입력 받습니다. scv = [12, 10, 4]
- scv의 체력이 60까지이므로 60의 크기에 n차원 dp 배열을 생성합니다. [[[0,0 ,,, (60개)]], ,,, (60개)]] ,,,, (60개)]
- dp에는 체력에 따른 맞은 최소 횟수가 들어갑니다.
- dp[scv[0]][scv[1]][scv[2]] = 1 -> dp[12][10][4] = 1 로 초기 값을 세팅해줍니다. (나중에 빼줌)
- comb는 scv들이 맞을수 있는 공격의 경우의 수를 나열해 놓았습니다.
- dp를 60, 60, 60 부터 순회합니다. 그러면 [12][10][4] (초기값) 그 위에는 pass 되겠죵
- dp[12][10][4] = 1 로 초기화된 값을 만나면 comb에 있는 값을 순회합니다.
- 12, 10, 4 였는데 9, 3, 1의 데미지를 받았다
- 12, 10, 4 였는데 9, 1, 3의 데미지를 받았다 등
- dp[3][7][3] 이 0 이거나 (이 체력에 처음 도달한 경우) or 그 전보다 적게 맞았으면 ([12][10][4] = 1 인데 [3][7][3] = 3이상 이면) 그 전에 맞은 횟수 + 1이 최소이므로 갱신해줍니다.
- 그 후 모든 scv 체력이 0,0,0 인 값에서 맨 처음 초기 세팅값 1을 빼줍니다.
스타크래프트는 여전히 하고싶네요 :)
이게 맞나 싶을정도로 다 돌려서 해봤는데 맞긴 맞았다.
scv는 1 ~ 3마리이므로 3차원 배열을 선언해주고 1마리나 2마리일 경우는 0으로 채워주면 된다.
for문 3개를 돌아가면서 공격(9,3,1) 3개 조합
comb = [(9, 3, 1), (9, 1, 3), (3, 9, 1), (3, 1, 9), (1, 9, 3), (1, 3, 9)]을 하나씩 빼주면서 0이하일땐 0이되게 계산해주면 된다.
그리고 dp에 저장하면된다.
스타크래프트하고 싶다.
'Coding test' 카테고리의 다른 글
[백준/11048/파이썬] 이동하기 - DP (0) | 2023.01.15 |
---|---|
[백준/12026/파이썬] BOJ거리 (0) | 2023.01.14 |
[백준/6603/파이썬] 로또 (0) | 2023.01.12 |
[백준/11723/파이썬] 집합 (0) | 2023.01.11 |
[백준/10972/파이썬] 다음 순열 (0) | 2023.01.10 |