강의로 돌아가기
전현서

16~20번 시간초과 질문합니다.

정답은 맞추는데..

마지막 5개의 케이스에서

DP가 거의 제대로 역할을 수행하지 못하는 것 같습니다.

고민을 열심히 해보았지만,

도저히 모르겠습니다.

DP를 어떤 식으로 개선해야 중복을 확실히 거를 수 있는지 도와주시면 감사하겠습니다.

작성중인 코드―solution.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
def solution(numbers):

    def dfs(idx, L, R, cost):

        if idx == len(numbers): #end
            return

        GOAL = int(numbers[idx])
        L_COST = weight(L, GOAL)
        R_COST = weight(R, GOAL)

        #recursive
        if R != GOAL:
            if cost + L_COST < dp[idx][GOAL][R]: #left
                dp[idx][GOAL][R] = cost + L_COST
                dfs(idx+1, GOAL, R, cost + L_COST)

        if L != GOAL:
            if cost + R_COST < dp[idx][L][GOAL]: #right
                dp[idx][L][GOAL] = cost + R_COST
                dfs(idx+1, L, GOAL, cost + R_COST)

    def weight(start, end):
        start = pad[start]
        end = pad[end]
        diff = [abs(end[0]-start[0]), abs(end[1]-start[1])]
        common = min(diff)
        other = max(diff)
        return max(common * 3 + ((other - common) * 2), 1)

    answer = 987654321
    pad = {0: (4, 2)}
    INF = 987654321
    L = 4
    R = 6

    for i in range(1, 4):
        for j in range(1, 4):
            pad[j + ((i-1) * 3)] = (i, j)

    dp = [[[INF for i in range(10)] for j in range(10)] for k in range(len(numbers))]

    dfs(0, L, R, 0)

    for i in range(10):
        for j in range(10):
            answer = min(answer, dp[len(numbers)-1][i][j])

    return answer
  • 전현서

    BFS로 바꾸니까 그냥 해결됬네용.. 뭐지??

    전현서―2023.02.08 07:21
1 개의 답변
최진균

지금 짜여진 코드를 보면 dp를 사용해서 rank k에서 (L, R)의 위치에 있는 score의 최솟값을 가지는 좌표에서만 재귀함수를 실행하는 방식으로 진행하고 있어요.
예제 1756을 보면 경로는 16가지가 나오지만 마지막에 위치한 곳은 7가지로 score의 최솟값만 가지고 나머지를 버리기 때문에 재귀함수를 많이 줄일 수 있어요.

그런데 dfs를 사용하면 이전 rank를 모두 비교하여 중복을 제거하는 과정을 하기도 전에
다음 rank를 탐색하기 때문에 완전탐색 경로 수의 절반이 되어야 rank2가 비교가 완료되고
경로 수의 3/4가 되어야 rank3가 비교가 완료되기 때문에 결국 중복을 제거하는 과정이 무의미해 지게 되요.

bfs을 사용하면 이전 rank을 모두 탐색한 다음에야 다음 rank로 넘어가기 때문에
다음 rank에 대해서 수행할 재귀함수가 크게 줄어들게 되요.

당장에 1756만 보아도 만약 5번째 숫자가 있었다면
dfs는 거의 16개 모든 경우에 대해서 재귀함수가 실행되지만
bfs는 7개의 경우에 대해서만 다음 반복문이 실행되서 dfs의 절반정도만 실행하는 것으로
최솟값을 구할 수가 있어요.

numbers이 길이가 5만 되도 bfs가 dfs보다 실행횟수가 반으로 줄어드는데
100,000이라면 엄청나게 줄어들지 않을까요?

dfs와 bfs 탐색순서 간단비교
dfs
L
LL
LLL
LLLL
LLLR
LLRR
LLRL
LRRR

bfs
L
R
LL
LR
RL
RR
LLL
LLR
LRL
LRR

  • 전현서

    오오 대박입니다.. 너무 대단하십니다. 확실히 bfs로 하면 경우의 수가 많이 줄겠군요!

    전현서―2023.02.11 07:28
답변 쓰기
이 입력폼은 마크다운 문법을 지원합니다.