AOJ - PACKING
냅색 문제인데, 정답을 역추적 해야한다. 역추적하는 방법엔 여러가지가 있겠지만, 일단 슬라이딩 윈도우로 1차원 배열만 선언해놓고 구할 순 없다는 것이다.
무조건 2차원으로 $\mathit{choice}[i][w]$ 를 두고 $i$ 번째 아이템까지 쓸 수 있고 무게 $w$를 쓸 수 있을 때 마지막으로 고른 것 이라는 배열을 관리한다.
$i=n-1 ~\&~ w=W$ 일 때가 항상 최대값이고, 이때부터 역추적을 시작해준다.
$\mathit{choice}[n-1][W]=k$ 라면 일단 마지막으로 고른 아이템은 $k$이고 다음은$\mathit{choice}[k-1][W-W_k]$ 로 점프하면 된다.
이렇게 반복문으로 구하지않고 재귀함수로 구할 수 있는 방법이 책에 소개된다.
struct item {
string name;
int w, v;
};
void solve() {
int n, w;
cin >> n >> w;
vector<item> arr;
for (int i = 0; i < n; i++) {
item k;
cin >> k.name >> k.w >> k.v;
arr.pb(k);
}
vvi dp(n, vi(w + 1));
vvi choice(n, vi(w + 1, -1));
for (int j = arr[0].w; j <= w; j++) {
dp[0][j] = arr[0].v;
choice[0][j] = 0;
}
for (int i = 1; i < n; i++) {
for (int j = 0; j <= w; j++) {
dp[i][j] = dp[i - 1][j];
choice[i][j] = choice[i - 1][j];
if (j >= arr[i].w && dp[i - 1][j - arr[i].w] + arr[i].v > dp[i][j]) {
dp[i][j] = dp[i - 1][j - arr[i].w] + arr[i].v;
choice[i][j] = i;
}
}
}
cout << dp[n - 1][w] << ' ';
vs ans;
int a = n - 1;
int b = w;
while (a >= 0 && b > 0 && choice[a][b] != -1) {
int pa = a;
ans.pb(arr[choice[a][b]].name);
a = choice[pa][b] - 1;
b -= arr[choice[pa][b]].w;
}
reverse(all(ans));
cout << sz(ans) << endl;
for (string s: ans) cout << s << endl;
}
Comments