QUANTIZE (중하, p. 244)

난이도가 ‘중’으로 되어있었지만, 어렵진 않았던 문제 → 그래서 ‘중하’로 낮춤.

N개의 숫자들을 정렬한 다음, 아래의 2가지 memoization이 필요하다.

  1. lp[b][e] = index [b,e] 구간을 숫자 1개로 양자화 할 때 $\sum(오차^{2})$의 최소 값
  2. dp[x][s] = index x까지 s개로 양자화 → 점화식: dp[x][s] = dp[i][s-1] + lp[i][x] (단, 0<i<x)

image.png

#include <bits/stdc++.h>
using namespace std;
int v[101];
int dp[101][11];
bool chk[101][11];
const int INF = 0x3f3f3f3f;
int lp[101][101];
int GetMinSqSum(int b, int e) {
    if(b == e) return 0;
    int& ret = lp[b][e];
    if(ret >= 0) return ret;

    ret = INF;
    for(int i = v[b]; i <= v[e]; i++) {
        int sum = 0;
        for(int j = b; j <= e; j++) {
            sum += (v[j] - i) * (v[j] - i);
        }
        ret = min(ret, sum);
    }
    return ret;
}
int f(int x, int s) {
    if(x == 0 && s >= 0) return 0;
    else if(s < 0) return INF;

    int& ret = dp[x][s];
    if(chk[x][s]) return ret;
    chk[x][s] = true;

    if(s == 1) return ret = GetMinSqSum(1, x);

    ret = INF;
    for(int i = x; i >= 1; i--) {
        ret = min(ret, GetMinSqSum(i, x) + f(i - 1, s - 1));
    }
    return ret;
}
int main() {
    ios::sync_with_stdio(false); cin.tie(0);
    int tc; cin >> tc;
    while(tc--) {
        int n, s; cin >> n >> s;
        for(int i = 1; i <= n; i++) {
            cin >> v[i];
        }
        sort(v + 1, v + n + 1);
        memset(chk, false, sizeof(chk));
        memset(lp, -1, sizeof(lp));

        printf("%d\n", f(n, s));
    }

    return 0;
}