DP Illustration
// 先读题
Complete Search(TLE)
Top-Down DP(AC)
#include <bits/stdc++.h>
using namespace std;
int T, M, C;
int price[25][25];
int memo[25][210];
int shop(int u, int remain){
if (remain < 0) return -1;
if (u == C) return M - remain;
int &ret = memo[u][remain];
if (ret != -1) return ret;
for (int model = 1; model <= price[u][0]; model++)
ret = max(ret, shop(u + 1, remain - price[u][model]));
return ret;
}
int main(){
cin >> T;
while (T--){
cin >> M >> C;
for (int i = 0; i < C; i++){
cin >> price[i][0]; // 个数
for (int j = 1; j <= price[i][0]; j++) cin >> price[i][j];
}
memset(memo, -1, sizeof memo);
int ret = shop(0, M);
if (ret < 0) cout << "no solution" << '\n';
else cout << ret << '\n';
}
return 0;
}
Bottom-Up DP(AC)
#include <bits/stdc++.h>
using namespace std;
int T, M, C;
int price[25][25];
bool reachable[25][210];
int main(){
cin >> T;
while (T--){
cin >> M >> C;
for (int i = 0; i < C; i++){
cin >> price[i][0];
for (int j = 1; j <= price[i][0]; j++)
cin >> price[i][j];
}
memset(reachable, false, sizeof reachable);
// base cases
for (int j = 1; j <= price[0][0]; j++)
if (M - price[0][j] >= 0) reachable[0][M - price[0][j]] = true;
for (int i = 1; i < C; i++)
for (int money = 0; money < M; money++)
if (reachable[i - 1][money]){ // 第i-1层的剩余money是可达的
for (int j = 1; j <= price[i][0]; j++)
if (money >= price[i][j]) // 剩余money够买第j个物品的
reachable[i][money - price[i][j]] = true;
}
int money = 0;
while (money <= M && !reachable[C - 1][money]) money++;
if (money == M + 1) cout << "no solution" << '\n';
else cout << M - money << '\n';
}
return 0;
}
// 利用滚动数组优化
#include <bits/stdc++.h>
using namespace std;
int T, M, C;
int price[25][25];
bool reachable[2][210];
int main(){
cin >> T;
while (T--){
cin >> M >> C;
for (int i = 0; i < C; i++){
cin >> price[i][0];
for (int j = 1; j <= price[i][0]; j++)
cin >> price[i][j];
}
memset(reachable, false, sizeof reachable);
// base cases
for (int j = 1; j <= price[0][0]; j++)
if (M - price[0][j] >= 0) reachable[0 & 1][M - price[0][j]] = true;
for (int i = 1; i < C; i++){
// 当前第i层的可达状态清空一下,避免和之前的混用
memset(reachable[i & 1], false, sizeof reachable[i & 1]);
for (int money = 0; money < M; money++)
if (reachable[(i - 1) & 1][money]){ // 第i-1层的剩余money是可达的
for (int j = 1; j <= price[i][0]; j++)
if (money >= price[i][j]){ // 剩余money够买第j个物品的
reachable[i & 1][money - price[i][j]] = true;
}
}
}
int money = 0;
while (money <= M && !reachable[(C - 1) & 1][money]) money++;
if (money == M + 1) cout << "no solution" << '\n';
else cout << M - money << '\n';
}
return 0;
}
// Note that for this problem, the memory savings are not significant.
// For harder DP problems,
// for example where there might be thousands of garment models instead of 20,
// this space saving trick can be important.
Top-Down verus Bottom-Up Dp
Displaying the Optimal Solution
#include <bits/stdc++.h>
using namespace std;
int T, M, C;
int price[25][25];
int memo[25][210];
int shop(int u, int remain){
if (remain < 0) return -1;
if (u == C) return M - remain;
int &ret = memo[u][remain];
if (ret != -1) return ret;
for (int model = 1; model <= price[u][0]; model++)
ret = max(ret, shop(u + 1, remain - price[u][model]));
return ret;
}
void print_shop(int u, int remain){
if (remain < 0 || u == C) return ;
for (int model = 1; model <= price[u][0]; model++){
if (shop(u + 1, remain - price[u][model]) == memo[u][remain]){
printf("%d%c", price[u][model], u == C - 1 ? '\n' : ' ');
print_shop(u + 1, remain - price[u][model]);
break;
}
}
}
int main(){
cin >> T;
while (T--){
cin >> M >> C;
for (int i = 0; i < C; i++){
cin >> price[i][0]; // 个数
for (int j = 1; j <= price[i][0]; j++) cin >> price[i][j];
}
memset(memo, -1, sizeof memo);
int ret = shop(0, M);
if (ret < 0) cout << "no solution" << '\n';
else cout << ret << '\n';
print_shop(0, M);
}
return 0;
}
Remarks Aboubt Dynamic Programming in Programming Contests