动态规划

很多[最优解]的问题都可以考虑使用动态规划解决

动态规划包括两个核心思想

  1. 状态转移方程

是指把一个大问题分解为多个重叠的子问题,寻找重叠子问题之间的关系
比如菲薄拉起数列的状态转移方案


如果4. 动态规划算法 - 图1表示斐波拉契数列的第n位的值
则有4. 动态规划算法 - 图2


在使用动态规划时,最苦难的就是找到状态转移方程

  1. db 缓存表

在求解的过程中,可能会遇到对相同的参数多次求解,为避免重复计算,可以使用缓存表将解值缓存下来

0-1背包问题

有一个背包,容积为c

给定一个物品列表: [o1,o2,o3,o4,...],每个物品都有两个属性,分别是价值和体积,例如{v:10,p:5}

问: 应该如何选择装入背包的物品,使得背包中的物品的总价值最大?

基础版

  1. /***
  2. *
  3. * 获取0-1背包问题的最优解
  4. * @param {Number} c背包体积
  5. * @param {{v:Number,p:Number}[]} list 物品列表
  6. * @returns {Number} 返回最大值
  7. *
  8. *
  9. */
  10. function package(c, list) {
  11. /**
  12. * @param {Number} i
  13. * @param {Number} rest;
  14. */
  15. function _package(i, rest) {
  16. // 如果不从当前的物品列表拿
  17. if (i >= list.length) {
  18. return 0;
  19. }
  20. const currPro = list[i];
  21. if (currPro.v > rest) {
  22. // 商品的体积大于剩余的空间了,商品一定不能拿,拿下一个
  23. return _package(i + 1, rest)
  24. } else {
  25. // 当选择这件物品的时候
  26. const selected = currPro.p + _package(i + 1, rest - currPro.v);
  27. // 当不选这件物品的时候胡
  28. const unSelected = _package(i + 1, rest);
  29. return Math.max(selected, unSelected)
  30. }
  31. }
  32. return _package(0, c)
  33. }
  34. const list = [
  35. { v: 10, p: 5 },
  36. { v: 7, p: 4 },
  37. { v: 11, p: 8 },
  38. { v: 9, p: 6 },
  39. { v: 2, p: 1 },
  40. { v: 17, p: 20 },
  41. { v: 25, p: 30 },
  42. ]
  43. const c = 40;
  44. const result = package(c, list);
  45. console.log('result', result)

升级版

  1. /**
  2. *
  3. * @param {Number} c 背包的体积
  4. * @param {Array} rest 剩余商品
  5. * @returns {{value:Number,choose:Number []}} max 最大值
  6. */
  7. function package(c, rest) {
  8. /**
  9. *
  10. * @param {Number} n 开始拿的位置
  11. * @param {Number} rest 剩余空间
  12. */
  13. function _package(n, rest) {
  14. // 超出可以挑选商品的范围
  15. if (n >= list.length) {
  16. return {
  17. value: 0,
  18. choose: []
  19. }
  20. }
  21. // 获取当前商品
  22. const product = list[n];
  23. // 当前商品的体积大于背包剩余的体积
  24. if (product.v > rest) {
  25. const next = _package(n + 1, rest);
  26. return {
  27. value: next.value,
  28. choose: [0, ...next.choose]
  29. }
  30. } else {
  31. // 选择当前物商品的价值
  32. let next = _package(n + 1, rest - product.v);
  33. let select = {
  34. value: product.p + next.value,
  35. choose: [1, ...next.choose]
  36. }
  37. // 不选择当前物品的机制
  38. next = _package(n + 1, rest);
  39. let unselect = {
  40. value: next.value,
  41. choose: [0, ...next.choose]
  42. }
  43. if (select.value > unselect.value) {
  44. return select;
  45. } else {
  46. return unselect;
  47. }
  48. }
  49. }
  50. return _package(0, c)
  51. }
  52. const list = [
  53. { v: 10, p: 5 },
  54. { v: 7, p: 4 },
  55. { v: 11, p: 8 },
  56. { v: 9, p: 6 },
  57. { v: 2, p: 1 },
  58. { v: 17, p: 20 },
  59. { v: 25, p: 30 },
  60. ]
  61. const c = 40;
  62. const result = package(c, list);
  63. console.log('result', result)

至尊版

  1. /**
  2. *
  3. * @param {Number} c 背包的体积
  4. * @param {Array} rest 剩余商品
  5. * @returns {{value:Number,choose:Number []}} max 最大值
  6. */
  7. function package(c, rest) {
  8. // 缓存
  9. const dp = {}
  10. /**
  11. *
  12. * @param {Number} n 开始拿的位置
  13. * @param {Number} rest 剩余空间
  14. */
  15. function _package(n, rest) {
  16. // 超出可以挑选商品的范围
  17. if (n >= list.length) {
  18. return {
  19. value: 0,
  20. choose: []
  21. }
  22. }
  23. const key = `${n}-${rest}`;
  24. if (dp[key]) {
  25. return dp[key];
  26. }
  27. // 获取当前商品
  28. const product = list[n];
  29. // 当前商品的体积大于背包剩余的体积
  30. if (product.v > rest) {
  31. const next = _package(n + 1, rest);
  32. dp[key] = {
  33. value: next.value,
  34. choose: [0, ...next.choose]
  35. }
  36. } else {
  37. // 选择当前物商品的价值
  38. let next = _package(n + 1, rest - product.v);
  39. let select = {
  40. value: product.p + next.value,
  41. choose: [1, ...next.choose]
  42. }
  43. // 不选择当前物品的机制
  44. next = _package(n + 1, rest);
  45. let unselect = {
  46. value: next.value,
  47. choose: [0, ...next.choose]
  48. }
  49. if (select.value > unselect.value) {
  50. dp[key] = select;
  51. } else {
  52. dp[key] = unselect;
  53. }
  54. }
  55. return dp[key];
  56. }
  57. const result = _package(0, c);
  58. console.log('dp', dp)
  59. return result;
  60. }
  61. const list = [
  62. { v: 10, p: 5 },
  63. { v: 7, p: 4 },
  64. { v: 11, p: 8 },
  65. { v: 9, p: 6 },
  66. { v: 2, p: 1 },
  67. { v: 17, p: 20 },
  68. { v: 25, p: 30 },
  69. ]
  70. const c = 40;
  71. const result = package(c, list);
  72. console.log('result', result)