DuoDuo 有 N 部想看的電影(N ≤ 100),每部有時長 Tᵢ 和喜愛值 Vᵢ。爺爺允許看 L 分鐘(L ≤ 1000)。商店**恰好賣 M 部**(M ≤ N)。選 M 部電影,總時長 ≤ L,最大化總喜愛值。若無法恰好看完 M 部輸出 0。
#include <cstdio>
#include <cstring>
#include <algorithm>
using namespace std;
const int INF = -0x3f3f3f3f;
const int MAXN = 105;
const int MAXL = 1005;
int dp[MAXN][MAXL];
int T[MAXN], V[MAXN];
int main() {
int cas; scanf("%d", &cas);
while (cas--) {
int N, M, L; scanf("%d%d%d", &N, &M, &L);
for (int i = 0; i < N; i++) scanf("%d%d", &T[i], &V[i]);
for (int i = 0; i <= M; i++)
for (int j = 0; j <= L; j++)
dp[i][j] = INF;
dp[0][0] = 0;
for (int k = 0; k < N; k++) {
for (int i = M; i >= 1; i--) {
for (int j = L; j >= T[k]; j--) {
if (dp[i-1][j-T[k]] != INF)
dp[i][j] = max(dp[i][j], dp[i-1][j-T[k]] + V[k]);
}
}
}
int ans = 0;
for (int j = 0; j <= L; j++)
ans = max(ans, dp[M][j]);
if (ans > 0) printf("%d\n", ans);
else printf("0\n");
}
return 0;
}
| 細節 | 處理 |
|---|---|
| 恰好 M 部 | 第一維狀態為選擇數量,初始 `dp[0][0]=0`,其餘 `-INF` |
| 總時長 ≤ L | 最後掃描 `dp[M][0..L]` 取最大值,而非只看 `dp[M][L]` |
| 無解輸出 0 | `ans` 初始 0,若所有 `dp[M][j]` 均為 `-INF` 則輸出 0 |
| 逆序更新 | 防止同一電影被多次選擇(01 背包特性) |
HDU 3496 是**二維 01 背包 + 恰裝滿一維**的標準模板題。關鍵在於:狀態定義包含「選擇數量」,初始化用 `-INF` 標記不可達,轉移逆序,最後在容量上界內取最大值而非要求恰好裝滿。同類題見 POJ 1014、HDU 2602 等。