01背包问题

    朴素版:(二维数组)

状态表示: dp[i][j]:从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案(n:物品数量,m:最大体积)

状态计算: dp[i][j] = max ( dp[i-1][j] , dp[i-1][j-vi]+wi )  // 由含i和不含i两个子集合计算而来(vi:物品体积,wi:物品价值)

核心代码:

int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
if(v[i] >= j) dp[i][j] = max(dp[i][j], dp[i-1][j-v[i]] + w[i]);
}
}

空间优化版:(滚动数组,二维数组优化至一维)

  状态表示:dp[j]:在外循环的第i层时,表示从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,n层循环后,dp[m]就是最终答案

  状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi )  // 由含i和不含i两个子集合计算而来

  核心代码:

int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N]; void keyCode()
{
for(int i = 1; i <= n; i++)
// 反向遍历, 否则dp[j-v[i]]可能为dp[i][j-v[i]](用更新后的值来更新导致出错)
for(int j = m; j >= v[i]; j--)
dp[j] = max(dp[j], dp[j-v[i]] + w[i]); }

完全背包问题

朴素版:(二维数组)

  状态表示:dp[i][j]:从前i种物品中选择(每种物品可以任选个数)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案

  状态计算:dp[i][j] = max ( dp[i-1][j] , dp[i][j-vi]+wi )

    证明:dp[i][j] = max ( dp[i-1][j] , dp[i-1][j-vi]+w, dp[i-1][j-2vi]+2wi , dp[i-1][j-3vi]+3w, ...... )

       dp[i][j-vi] = max (               dp[i-1][j-vi] ,      dp[i-1][j-2vi]+w,   dp[i-1][j-3vi]+2w,  ...... )

       Thus,dp[i][j-vi]+wi = max ( dp[i-1][j-vi]+wi , dp[i-1][j-2vi]+2w, dp[i-1][j-3vi]+3w,  ...... )

       Thus,dp[i][j] = max ( dp[i-1][j] , dp[i][j-vi]+wi )

  核心代码:

int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
if(j >= v[i]) dp[i][j] = max(dp[i][j], dp[i][j-v[i]] + w[i]);
}
}

空间优化版:(滚动数组,二维数组优化至一维)

  状态表示:dp[j]:在外循环的第i层时,表示从前i种物品中选择(每种物品可以任选个数)且总体积不超过j的集合的最大价值,n层循环后,dp[m]就是最终答案

  状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi )  // 由含i和不含i两个子集合计算而来

  核心代码:

int n, m; // n:物品数量, m:最大体积
int v[N], w[N], dp[N]; void keyCode()
{
for(int i = 1; i <= n; i++)
// 正向遍历, 使得dp[j-v[i]]为dp[i][j-v[i]]
for(int j = v[i]; j <= m; j++)
dp[j] = max(dp[j], dp[j-v[i]] + w[i]); }

多重背包问题

朴素版:(二维数组+三重循环)

  状态表示:dp[i][j]:从前i种物品中选择(每种物品最多选择si个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案

  状态计算:dp[i][j] = max ( dp[i-1][j],dp[i-1][j-v]+w,dp[i-1][j-2v]+2w,...,dp[i-1][j-sv]+sw )

  核心代码:

int n, m; // n:物品数量, m:最大体积
int v[N], w[N], s[S];
int dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
for(int j = 0; j <= m; j++)
for(int k = 0; k <= s[i] && k * v[i] <= j; k++)
dp[i][j] = max(dp[i][j], dp[i-1][j-k*v[i]] + k*w[i]);
}

优化版:(一维数组+二重循环)

  二进制优化:对于每种物品,将其按2的次幂大小拆分合并,如s[i]=12时,方案为:第1个物品合并,第2~3个物品合并,第4~7个物品合并,第8~12个物品合并(1,2,4,5)。这样,就将多重背包问题转化成01背包问题

  状态表示:dp[j]:在外循环的第i层时,表示从前i个物品中选择(每个物品只能选0或1个)且总体积不超过j的集合的最大价值,n层循环后(n为问题转化后的新n),dp[m]就是最终答案

  状态计算:dp[j] = max ( dp[j] , dp[j-vi]+wi )

  核心代码:

int n, m;
int v[N], w[N], dp[M]; // N:maxn * logmaxs void keyCode()
{
int cnt = 0;
for(int i = 1; i <= n; i++)
{
int a, b, s; // vi, wi, si
cin >> a >> b >> s;
int p = 1;
while(p <= s)
{
cnt ++;
v[cnt] = a * p, w[cnt] = b * p;
s -= p, p *= 2;
}
if(s > 0)
{
cnt ++;
v[cnt] = a * s, w[cnt] = b * s;
}
}
n = cnt; // n --> 问题转化后的新n
for(int i = 1; i <= n; i++)
for(int j = m; j >= v[i]; j--) // 反向遍历
dp[j] = max(dp[j], dp[j-v[i]] + w[i]);
}

 

分组背包问题

朴素版:(二维数组)

  状态表示:dp[i][j]:从前i组物品中选择(每组物品中只能选择0或1个)且总体积不超过j的集合的最大价值,则dp[n][m]就是最终答案

  状态计算:dp[i][j] = max ( dp[i-1][j],dp[i-1][j-vi,1]+wi,1,dp[i-1][j-vi,2]+wi,2,dp[i-1][j-vi,3]+wi,3,... )

  核心代码:

int n, m; // n:物品数量, m:最大体积
int s[N], v[N][S], w[N][S];
int dp[N][M]; void keyCode()
{
for(int i = 1; i <= n; i++)
{
for(int j = 0; j <= m; j++)
{
dp[i][j] = dp[i-1][j];
for(int k = 1; k <= s[i]; k++)
if(v[i][k] <= j)
dp[i][j] = max(dp[i][j], dp[i-1][j-v[i][k]] + w[i][k]);
}
}
}

    空间优化版:(滚动数组,二维数组优化至一维)

int n, m; // n:物品数量, m:最大体积
int s[N], v[N][S], w[N][S];
int dp[M]; void keyCode()
{
for(int i = 1; i <= n; i++)
{
for(int j = m; j >= 0; j--) // 反向遍历
{
for(int k = 1; k <= s[i]; k++)
if(v[i][k] <= j)
dp[j] = max(dp[j], dp[j-v[i][k]] + w[i][k]);
}
}
}

最新文章

  1. Javascript与ECMAScript
  2. Quartz.NET开源作业调度框架系列(一):快速入门step by step
  3. POJ 1386 Play on Words(欧拉图的判断)
  4. EXTJS 6 新特性(译文)
  5. Spring的事务传播属性,数据库的隔离级别
  6. cmd下运行java文件时,找不到或无法加载主类的解决方法
  7. SQL打印全年日历
  8. HeadFirst SQL 读书摘要
  9. 做的简单的一个静态web服务器,遇到个bug, 提示osError,这点一不小心就错了,特地记下来,加深记忆,socket须先绑定,再listen,如果是先listen再绑定,系统会自动分配一个端口,而程序绑定不了
  10. SQL 查看SQL语句的执行时间 直接有效的方法
  11. Python平时代码的一些知识
  12. s5-6 Linux 标准输出 系统优化 目录结构
  13. [Oracle]ORA-600[kdBlkCheckError]LOB坏块处理
  14. SQL注入之Sqli-labs系列第七篇(基于root权限读写注入)
  15. About The Algorithm Simplification
  16. hdu 4857 Little Devil I
  17. ios开发之--NSDictionary和NSData之间的互转/NSString和NSData之间的互转
  18. SharePoint 2013的100个新功能之内容管理(四)
  19. HTML5实现输入密码(六个格子)
  20. C#程序集系列03,引用多个module

热门文章

  1. IT人的修炼之路
  2. Docker系列教程05-Docker数据卷(Data Volume)学习
  3. Flask01 第一个flask项目
  4. Spring 源码(11)Spring Bean 的创建过程(2)
  5. API Schema in kubernetes
  6. 23. Merge k Sorted Lists - LeetCode
  7. AJAX——POST请求
  8. 03-数据结构(C语言版)
  9. MySQLDocker 主从复制搭建
  10. anaconda遇到:Solving environment: failed with initial frozen solve. Retrying with flexible solve.问题