BOJ 12932 - 노래방

image.png

$dp[i][p_1]=$ $i$ 번째 음을 볼 차례이고 더 이전에 불렀던 사람이 $p_1$ 번째 음을 불렀을 때 끝까지 부르는데 최소값

라고 두고, $p_1=0$ 일 때는 아직 안 부른 것으로 취급한다.

시간복잡도 $O(n^2)$ 로 구할 수 있다.

int n, a[2001], dp[2001][2001];  
  
// i 번째 음을 볼 차례이고 더 일찍 부른 사람이 마지막으로 p를 불렀을 때 끝까지 부르는데 최소값  
int fn(int i, int p1) {  
   if (i == n + 1) return 0;  
  
   int &ret = dp[i][p1];  
   if (~ret) return ret;  
   ret = 1e9;  
  
   assert(p1 == 0 || p1 < i - 1);  
   int a_cost = p1 == 0 ? 0 : abs(a[i] - a[p1]);  
   int p2 = i - 1;  
   int b_cost = p2 == 0 ? 0 : abs(a[i] - a[i - 1]);  
  
   // 더 이전에 부른 사람이 부르는 경우  
   ret = a_cost + fn(i + 1, p2);  
   // 더 후에 부른 사람이 부르는 경우  
   ret = min(ret, b_cost + fn(i + 1, p1));  
  
   return ret;  
}  
  
void solve() {  
   memset(dp, -1, sizeof dp);  
   cin >> n;  
   for (int i = 1; i <= n; i++) cin >> a[i];  
   cout << fn(1, 0);  
}

Tags:

Categories:

Updated:

Comments