백준 13549번 숨바꼭질3 문제 바로가기

알고리즘 분류

  • DP
  • 다익스트라

 

풀이

점화식은 위치가 짝수일 때와 홀수일 때로 나뉜다.

  1. 짝수일 때
    • 1칸 이전 값 (가중치 1)
    • 절반 위치 (가중치 0)
  2. 홀수일 때
    • 1칸 이전 값 (가중치 1)
    • 1칸 앞(짝수)의 절반 위치(가중치 1)

 

하지만 홀수의 점화식에 의문이 들 수가 있다.
왜 1칸 앞의 절반만 고려할까? 문제에서는 앞이나 뒤로 1칸씩 이동할 수 있다고 했는데?
2로 나눈 값이 올림 또는 내림이 될 수 있는 거 아니야?
왜 "1칸 뒤(짝수)의 절반 위치"는 고려하지 않을까?

결론부터 말하자면 점화식에 1칸 뒤 절반 위치를 넣어도 결과는 동일하다.
하지만 의미 없는 연산이다. 이유는 "1칸 이전 값"과 중복되기 때문이다.

예를 들어 현재 위치가 9라고 가정해 보자.

  • 1칸 이전 값 → 9-1 = 8
  • 1칸 뒤(짝수)의 절반 위치 → (9-1)/2 = 4

 

중요한 사실은 2배 이동은 가중치가 그대로이다.

그렇기 때문에 8의 위치와 4의 위치 값이 같기 때문에

  • 8의 위치 = 4의 위치
  • 1칸 이전 값 = 1칸 뒤(짝수)의 절반 위치

홀수일 때 위 등식이 성립한다.

사실 처음에는 떠올리지 못했다.
정답 처리를 받았을 때는 점화식에 같이 포함시켰는데 생각해 보니 필요가 없었다.

 

풀이 코드

DP

#include <iostream>
using namespace std;
int main(){
    int n, k, dp[100001];
    cin>> n >> k;
    
    // 시작점에서 뒤로 이동
    for(int i = 0; i <= n; i++) 
    	dp[i] = n-i;
        
    // 앞으로 이동
    for(int i= n+1; i <= k; i++) {
    	// 1칸 이동
        dp[i] = dp[i-1] + 1; 
        
        // 2배 이동
        if(i%2 == 0) // 짝수
            dp[i] = min(dp[i], dp[i/2]);
        else // 홀수
            dp[i] = min(dp[i], dp[(i+1)/2] + 1);   
    }
        
    cout << dp[k];
}

 

다익스트라

#include<bits/stdc++.h>
using namespace std;

using pii = pair<int,int>;

bool visited[100001];

int main(){
    int n,k;
    priority_queue<pii, vector<pii>, greater<pii> > pq;
    
    cin >> n >> k;
    
    visited[n] = true;
    pq.push({0, n});

    while(!pq.empty()) {
        int cur=pq.top().second;
        int cost=pq.top().first;
        pq.pop();
        
        if(cur == k) {
            cout << cost;
            break;
        }
        // 점프
        if(cur*2 <= k+1 && !visited[cur*2]) {
            visited[cur*2] = true;
            pq.push({cost, cur*2});
        }
        // 앞으로
        if(cur+1 <=k && !visited[cur+1]) {
            visited[cur+1] = true;
            pq.push({cost+1, cur+1});
        }
        // 뒤로
        if(cur-1 >= 0 && !visited[cur-1]) {
            visited[cur-1] = true;
            pq.push({cost+1, cur-1});
        }
    }
}

 

후기

음.. 사실 이 문제를 처음 봤을 때 DP 밖에 떠오르지 않아서 힘들게 점화식을 구했다.
다익스트라로 푸는 방법이 있는지 떠올리지 못했다.
이번 문제야 다행히 풀렸지만 한 알고리즘에 꽂히면  헤어 나오지를 못하겠다.
만약 코테에서 떠오른 알고리즘으로 접근했는데 이 방법으로는 절대 풀 수 없으면... 생각만으로도 어지럽다

(+)
코드가 짧다고 다 좋은 건 아니지만 숏코딩 1등!

C++ 숏코딩 보러가기