• 一些动态规划dp简单基础题


    背包基础:

    01背包:每样东西只能选一个

    模板:滚动数组优化

    1. #include
    2. using namespace std;
    3. const int N = 1010;
    4. int v[N], w[N]; // 存第i个物品的体积和价值
    5. int n, m;
    6. int f[N]; // f存状态,行表示物品, 列表示背包大小
    7. int main()
    8. {
    9. cin >> n >> m;
    10. for (int i = 1; i <= n; i++)
    11. cin >> v[i] >> w[i];
    12. for (int i = 1; i <= n; i++) // i枚举物品
    13. for (int j = m; j >= v[i]; j -- ) // j枚举空间
    14. {
    15. f[j] = max(f[j], f[j - v[i]] + w[i]);
    16. }
    17. cout << f[m] << endl;
    18. return 0;
    19. }

    多重背包:每样东西能选s[i]个

    模板:

    1. #include
    2. using namespace std;
    3. const int N = 110;
    4. int n, m;
    5. int f[N];
    6. int main()
    7. {
    8. cin >> n >> m;
    9. for(int i = 1; i <= n; i ++ )
    10. {
    11. int v, w, s;
    12. cin >> v >> w >> s;
    13. for(int j = m; j >= 0; j -- )
    14. {
    15. for(int k = 0; k <= s && k * v <= j; k ++ )
    16. {
    17. f[j] = max(f[j], f[j - k * v] + k * w);
    18. }
    19. }
    20. }
    21. cout << f[m] << endl;
    22. return 0;
    23. }

    二进制优化:实际上是分堆,减少了i枚举数

    1. #include
    2. using namespace std;
    3. const int N = 2010, M = 12010;
    4. int n, m, cnt = 1;
    5. int f[N];
    6. int v[M], w[M];
    7. int main()
    8. {
    9. cin >> n >> m;
    10. //二进制堆
    11. for(int i = 1; i <= n; i ++ )
    12. {
    13. int a, b, s, k = 1;
    14. cin >> a >> b >> s;
    15. while(k <= s)
    16. {
    17. s -= k;
    18. v[cnt] = k * a;
    19. w[cnt ++ ] = k * b;
    20. k *= 2;
    21. }
    22. if(s > 0)
    23. {
    24. v[cnt] = s * a;
    25. w[cnt ++ ] = s * b;
    26. }
    27. }
    28. n = cnt;
    29. for(int i = 1; i <= n; i ++ )
    30. {
    31. for(int j = m; j >= v[i]; j -- )
    32. {
    33. f[j] = max(f[j], f[j - v[i]] + w[i]);
    34. }
    35. }
    36. cout << f[m] << endl;
    37. return 0;
    38. }

    完全背包:每样东西能选无限个

    模板:完全背包的的优化就在于推公式,由于是无限个,所以就可以同加来消元

    1. #include
    2. using namespace std;
    3. const int N = 1010;
    4. int v[N], w[N], f[N][N];
    5. int n, m;
    6. int main()
    7. {
    8. cin >> n >> m;
    9. for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i];
    10. /*
    11. 这个状态转移公式是这么推出来的
    12. f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i], f[i - 1][j - 2 * v[i]] + 2 * w[i], ...)
    13. f[i][j - v[i]] = max(f[i - 1][j - v[i]], f[i - 1][j - 2 * v[i]] + w[i], f[i - 1][j - 3 * v[i]] + 2 * w[i], ...);
    14. */
    15. for(int i = 1; i <= n; i ++ )
    16. for(int j = 1; j <= m; j ++ )
    17. {
    18. f[i][j] = f[i - 1][j];
    19. if(v[i] <= j) f[i][j] = max(f[i - 1][j], f[i][j - v[i]] + w[i]);
    20. }
    21. cout << f[n][m] << endl;
    22. return 0;
    23. }

    例题:

    小A点菜 - 洛谷

    01背包变式,求其选择方法种数。这里我选择f[j] = f[j] + f[j - x]  选择它的种数+不选择它的种数

    1. #include
    2. using namespace std;
    3. const int N = 1e4 + 10;
    4. int n, m;
    5. int f[N];
    6. int main()
    7. {
    8. cin >> n >> m;
    9. f[0] = 1;
    10. for(int i = 1; i <= n; i ++ )
    11. {
    12. int x;
    13. cin >> x;
    14. for(int j = m; j >= x; j -- )
    15. {
    16. f[j] += f[j - x];
    17. }
    18. }
    19. cout << f[m];
    20. return 0;
    21. }

    [NOIP2001 普及组] 装箱问题 - 洛谷

    也是个01背包问题,只不过我将f[]用于枚举此时能够装的体积了。

    1. #include
    2. using namespace std;
    3. const int N = 1e5 + 10;
    4. int n, m;
    5. int f[N];
    6. int main()
    7. {
    8. cin >> m >> n;
    9. for(int i = 1; i <= n; i ++ )
    10. {
    11. int x;
    12. cin >> x;
    13. for(int j = m; j >= x; j -- )
    14. {
    15. f[j] = max(f[j], f[j - x] + x);
    16. }
    17. }
    18. cout << m - f[m];
    19. return 0;
    20. }

    [USACO1.5] [IOI1994]数字三角形 Number Triangles - 洛谷

    这是个递推题,杨辉三角,该位置的最大路径值=左上+正上

    1. #include
    2. using namespace std;
    3. const int N = 1010;
    4. int n;
    5. int a[N][N], f[N][N];
    6. int main()
    7. {
    8. cin >> n;
    9. for (int i = 1; i <= n; i++)
    10. for (int j = 1; j <= i; j++)
    11. cin >> a[i][j];
    12. f[1][1] = a[1][1];
    13. for (int i = 2; i <= n; i++)
    14. {
    15. for (int j = 1; j <= i; j++)
    16. {
    17. f[i][j] = a[i][j] + max(f[i - 1][j - 1], f[i - 1][j]);
    18. }
    19. }
    20. int ans = 0;
    21. for (int i = 1; i <= n; i++)
    22. {
    23. ans = max(ans, f[n][i]);
    24. }
    25. cout << ans << endl;
    26. return 0;
    27. }

    [NOIP2005 普及组] 采药 - 洛谷

    经典01背包,板子题

    疯狂的采药 - 洛谷

    经典完全背包,板子题

    5 倍经验日 - 洛谷

    [NOIP2002 普及组] 过河卒 - 洛谷

    [NOIP1996 提高组] 挖地雷 - 洛谷

    这个题我是用有向图遍历过的,每次找一条挖地雷的路,找到最大路保存下来。

    1. #include
    2. #include
    3. using namespace std;
    4. const int N = 40, M = 2 * N;
    5. int n;
    6. int w[N];
    7. int e[M], ne[M], h[N], idx;
    8. bool st[N];
    9. int res, ans, stp;
    10. int path[N], rpath[N];
    11. void add(int a, int b)
    12. {
    13. e[idx] = b, ne[idx] = h[a], h[a] = idx ++;
    14. }
    15. bool check(int x)
    16. {
    17. if(ne[ne[h[x]]] == -1 || h[x] == -1)
    18. return true;
    19. }
    20. void dfs(int u, int cnt)
    21. {
    22. // st[u] = true;
    23. // cout << u << ' ';
    24. res += w[u];
    25. path[cnt] = u;
    26. if(check(u))
    27. {
    28. if(ans < res)
    29. {
    30. ans = res;
    31. stp = cnt;
    32. for(int i = 0; i <= cnt; i ++ )
    33. {
    34. rpath[i] = path[i];
    35. }
    36. }
    37. }
    38. for(int i = h[u]; i != -1; i = ne[i])
    39. {
    40. int j = e[i];
    41. int value = w[j];
    42. // if(!st[j])
    43. // {
    44. dfs(j, cnt + 1);
    45. // }
    46. }
    47. res -= w[u];
    48. }
    49. int main()
    50. {
    51. cin >> n;
    52. memset(h, -1, sizeof h);
    53. for(int i = 1; i <= n; i ++ )
    54. {
    55. cin >> w[i];
    56. }
    57. for(int i = 1; i < n; i ++ )
    58. {
    59. for(int j = i + 1; j <= n; j ++ )
    60. {
    61. int t;
    62. cin >> t;
    63. if(t) add(i, j);
    64. }
    65. }
    66. for(int i = 1; i <= n; i ++ ) dfs(i, 0);
    67. for(int i = 0; i <= stp; i ++ ) cout << rpath[i] << ' ';
    68. cout << endl;
    69. cout << ans << endl;
    70. return 0;
    71. }

  • 相关阅读:
    关于递归和回溯的一次深入思考
    【一起来学C++】————(2)类与对象(上)
    TCP机械臂控制
    T1066 满足条件的数累加(信息学一本通C++)
    mysql升级
    像追女神一样学好java~
    毕设-基于SpringBoot房屋租赁系统
    【Hack The Box】Linux练习-- Popcorn
    阿里三面:Redis大key怎么处理?
    React组件之间的通信方式总结(上)
  • 原文地址:https://blog.csdn.net/qq_74593128/article/details/133105369