欢迎访问 生活随笔!

生活随笔

当前位置: 首页 > 编程资源 > 编程问答 >内容正文

编程问答

自顶向下 与自底向上解决01 背包问题

发布时间:2025/6/15 编程问答 20 豆豆
生活随笔 收集整理的这篇文章主要介绍了 自顶向下 与自底向上解决01 背包问题 小编觉得挺不错的,现在分享给大家,帮大家做个参考.
01背包问题具体例子:假设现有容量10kg的背包,另外有3个物品,分别为a1,a2,a3。物品a1重量为3kg,价值为4;物品a2重量为4kg,价值为5;物品a3重量为5kg,价值为6。将哪些物品放入背包可使得背包中的总价值最大?


  这个问题有两种解法,动态规划和贪婪算法。本文仅涉及动态规划。


  先不套用动态规划的具体定义,试着想,碰见这种题目,怎么解决?


  首先想到的,一般是穷举法,一个一个地试,对于数目小的例子适用,如果容量增大,物品增多,这种方法就无用武之地了。


  其次,可以先把价值最大的物体放入,这已经是贪婪算法的雏形了。如果不添加某些特定条件,结果未必可行。


  最后,就是动态规划的思路了。先将原始问题一般化,欲求背包能够获得的总价值,即欲求前i个物体放入容量为m(kg)背包的最大价值c[i][m]——使用一个数组来存储最大价值,当m取10,i取3时,即原始问题了。而前i个物体放入容量为m(kg)的背包,又可以转化成前(i-1)个物体放入背包的问题。下面使用数学表达式描述它们两者之间的具体关系。


  表达式中各个符号的具体含义。


  w[i] :  第i个物体的重量;


  p[i] : 第i个物体的价值;


  c[i][m] : 前i个物体放入容量为m的背包的最大价值;


  c[i-1][m] : 前i-1个物体放入容量为m的背包的最大价值;


  c[i-1][m-w[i]] : 前i-1个物体放入容量为m-w[i]的背包的最大价值;


  由此可得:


      c[i][m]=max{c[i-1][m-w[i]]+pi , c[i-1][m]}(下图将给出更具体的解释)






 


 


    根据上式,对物体个数及背包重量进行递推,列出一个表格(见下表),表格来自(http://blog.csdn.net/fg2006/article/details/6766384?reload) ,当逐步推出表中每个值的大小,那个最大价值就求出来了。推导过程中,注意一点,最好逐行而非逐列开始推导,先从编号为1的那一行,推出所有c[1][m]的值,再推编号为2的那行c[2][m]的大小。这样便于理解。






    


    思路厘清后,开始编程序,C语言代码如下所示。


#include <stdio.h> int c[10][100]={0};void knap(int m,int n){int i,j,w[10],p[10];for(i=1;i<n+1;i++)scanf("%d,%d",&w[i],&p[i]);for(j=0;j<m+1;j++)for(i=0;i<n+1;i++){if(j<w[i]){c[i][j]=c[i-1][j];continue;}else if(c[i-1][j-w[i]]+p[i]>c[i-1][j])c[i][j]=c[i-1][j-w[i]]+p[i];elsec[i][j]=c[i-1][j];}} int main(){int m,n;int i,j;printf("input the max capacity and the number of the goods:\n");scanf("%d,%d",&m,&n);printf("Input each one(weight and value):\n");knap(m,n);printf("\n");for(i=0;i<=n;i++)for(j=0;j<=m;j++){printf("%4d",c[i][j]);if(m==j) printf("\n");} } 代码中,红色字体部分是自己写的,其余的参照了这篇博客http://blog.sina.com.cn/s/blog_6dcd26b301013810.html



自顶向下

#include <stdio.h> #include <tchar.h> #include <queue> #include "iostream" using namespace std; const int N = 4; const int W = 5; int weight[N] = {2, 1, 3, 2}; int value[N] = {3, 2, 4, 2}; int record[N][W]; void init() { for(int i = 0; i < N; i ++) { for(int j = 0; j < W; j ++) { record[i][j] = -1; } } } int solve(int i, int residue) { if(-1 != record[i][residue]) return record[i][residue]; int result = 0; if(i >= N) return result; if(weight[i] > residue) { record[i + 1][residue] = solve(i+1, residue); } else { result = max(solve(i+1, residue), solve(i+1, residue-weight[i]) + value[i]); } return record[i + 1][residue] = result; } int main() { init(); int result = solve(0, W); cout << result << endl; return 0; }



总结

以上是生活随笔为你收集整理的自顶向下 与自底向上解决01 背包问题的全部内容,希望文章能够帮你解决所遇到的问题。

如果觉得生活随笔网站内容还不错,欢迎将生活随笔推荐给好友。