image.png

DP Illustration

例题,Wedding shopping UVA-11450

  1. // 先读题

image.png
image.png
image.png

Complete Search(TLE)

image.png
image.png

Top-Down DP(AC)

image.png
image.png
image.png

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int T, M, C;
  4. int price[25][25];
  5. int memo[25][210];
  6. int shop(int u, int remain){
  7. if (remain < 0) return -1;
  8. if (u == C) return M - remain;
  9. int &ret = memo[u][remain];
  10. if (ret != -1) return ret;
  11. for (int model = 1; model <= price[u][0]; model++)
  12. ret = max(ret, shop(u + 1, remain - price[u][model]));
  13. return ret;
  14. }
  15. int main(){
  16. cin >> T;
  17. while (T--){
  18. cin >> M >> C;
  19. for (int i = 0; i < C; i++){
  20. cin >> price[i][0]; // 个数
  21. for (int j = 1; j <= price[i][0]; j++) cin >> price[i][j];
  22. }
  23. memset(memo, -1, sizeof memo);
  24. int ret = shop(0, M);
  25. if (ret < 0) cout << "no solution" << '\n';
  26. else cout << ret << '\n';
  27. }
  28. return 0;
  29. }

Bottom-Up DP(AC)

image.png
image.png

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int T, M, C;
  4. int price[25][25];
  5. bool reachable[25][210];
  6. int main(){
  7. cin >> T;
  8. while (T--){
  9. cin >> M >> C;
  10. for (int i = 0; i < C; i++){
  11. cin >> price[i][0];
  12. for (int j = 1; j <= price[i][0]; j++)
  13. cin >> price[i][j];
  14. }
  15. memset(reachable, false, sizeof reachable);
  16. // base cases
  17. for (int j = 1; j <= price[0][0]; j++)
  18. if (M - price[0][j] >= 0) reachable[0][M - price[0][j]] = true;
  19. for (int i = 1; i < C; i++)
  20. for (int money = 0; money < M; money++)
  21. if (reachable[i - 1][money]){ // 第i-1层的剩余money是可达的
  22. for (int j = 1; j <= price[i][0]; j++)
  23. if (money >= price[i][j]) // 剩余money够买第j个物品的
  24. reachable[i][money - price[i][j]] = true;
  25. }
  26. int money = 0;
  27. while (money <= M && !reachable[C - 1][money]) money++;
  28. if (money == M + 1) cout << "no solution" << '\n';
  29. else cout << M - money << '\n';
  30. }
  31. return 0;
  32. }

image.png

  1. // 利用滚动数组优化
  2. #include <bits/stdc++.h>
  3. using namespace std;
  4. int T, M, C;
  5. int price[25][25];
  6. bool reachable[2][210];
  7. int main(){
  8. cin >> T;
  9. while (T--){
  10. cin >> M >> C;
  11. for (int i = 0; i < C; i++){
  12. cin >> price[i][0];
  13. for (int j = 1; j <= price[i][0]; j++)
  14. cin >> price[i][j];
  15. }
  16. memset(reachable, false, sizeof reachable);
  17. // base cases
  18. for (int j = 1; j <= price[0][0]; j++)
  19. if (M - price[0][j] >= 0) reachable[0 & 1][M - price[0][j]] = true;
  20. for (int i = 1; i < C; i++){
  21. // 当前第i层的可达状态清空一下,避免和之前的混用
  22. memset(reachable[i & 1], false, sizeof reachable[i & 1]);
  23. for (int money = 0; money < M; money++)
  24. if (reachable[(i - 1) & 1][money]){ // 第i-1层的剩余money是可达的
  25. for (int j = 1; j <= price[i][0]; j++)
  26. if (money >= price[i][j]){ // 剩余money够买第j个物品的
  27. reachable[i & 1][money - price[i][j]] = true;
  28. }
  29. }
  30. }
  31. int money = 0;
  32. while (money <= M && !reachable[(C - 1) & 1][money]) money++;
  33. if (money == M + 1) cout << "no solution" << '\n';
  34. else cout << M - money << '\n';
  35. }
  36. return 0;
  37. }
  38. // Note that for this problem, the memory savings are not significant.
  39. // For harder DP problems,
  40. // for example where there might be thousands of garment models instead of 20,
  41. // this space saving trick can be important.

Top-Down verus Bottom-Up Dp

image.png
image.png

Displaying the Optimal Solution

image.png
image.png

  1. #include <bits/stdc++.h>
  2. using namespace std;
  3. int T, M, C;
  4. int price[25][25];
  5. int memo[25][210];
  6. int shop(int u, int remain){
  7. if (remain < 0) return -1;
  8. if (u == C) return M - remain;
  9. int &ret = memo[u][remain];
  10. if (ret != -1) return ret;
  11. for (int model = 1; model <= price[u][0]; model++)
  12. ret = max(ret, shop(u + 1, remain - price[u][model]));
  13. return ret;
  14. }
  15. void print_shop(int u, int remain){
  16. if (remain < 0 || u == C) return ;
  17. for (int model = 1; model <= price[u][0]; model++){
  18. if (shop(u + 1, remain - price[u][model]) == memo[u][remain]){
  19. printf("%d%c", price[u][model], u == C - 1 ? '\n' : ' ');
  20. print_shop(u + 1, remain - price[u][model]);
  21. break;
  22. }
  23. }
  24. }
  25. int main(){
  26. cin >> T;
  27. while (T--){
  28. cin >> M >> C;
  29. for (int i = 0; i < C; i++){
  30. cin >> price[i][0]; // 个数
  31. for (int j = 1; j <= price[i][0]; j++) cin >> price[i][j];
  32. }
  33. memset(memo, -1, sizeof memo);
  34. int ret = shop(0, M);
  35. if (ret < 0) cout << "no solution" << '\n';
  36. else cout << ret << '\n';
  37. print_shop(0, M);
  38. }
  39. return 0;
  40. }

Remarks Aboubt Dynamic Programming in Programming Contests

image.png
image.png