0-1背包问题的动态规划法与回溯法

0-1背包问题的动态规划法与回溯法一、动态规划状态转移方程:算法:例子:例:0-1背包问题。在使用动态规划算法求解0-1背包问题时,使用二维数组m[i][j]存储背包剩余容量为j,可选物品为i、i+1、……、n时0-1背包问题

大家好,又见面了,我是你们的朋友全栈君。

一、动态规划

状态转移方程:

 1 从前往后:
 2 if(j>=w[i])
 3     m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
 4 else
 5     m[i][j]=m[i-1][j];
 6  
 7 从后往前:
 8 if(j>=w[i])
 9     m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
10 else
11     m[i][j]=m[i+1][j];

算法:

 1 从前往后:
 2 for(int i=1;i<=n;i++)
 3     for(int j=1;j<=c;j++)
 4     {
 5         if(j>=w[i])
 6         {
 7             m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
 8         }
 9         else//这里没有考虑j<0的情况,因为算法中j取不到
10         {
11             m[i][j]=m[i-1][j];
12         }
13     }
14  
15 从后往前:
16 for(int i=n;i>=1;i--)
17     for(int j=1;j<=c;j++)
18     {
19         if(j>=w[i])
20         {
21             m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
22         }
23         else
24         {
25             m[i][j]=m[i+1][j];
26         }
27     }

例子:

例:0-1背包问题。在使用动态规划算法求解0-1背包问题时,使用二维数组m[i][j]存储背包剩余容量为j,可选物品为i、i+1、……、n时0-1背包问题的最优值。绘制

重量数组w = {4, 6, 2, 2, 5, 1},

价值数组v = {8, 10, 6, 3, 7, 2},

背包容量C = 12时对应的m[i][j]数组。(从前往后)

<span role="heading" aria-level="2">0-1背包问题的动态规划法与回溯法

例题代码 :

 1 #include<iostream>
 2 #include<cmath>
 3 #include<cstring>
 4 #define N 20
 5 using namespace std;
 6 int main()
 7 {
 8     int w[N]={0,4,6,2,2,5,1},v[N]={0,8,10,6,3,7,2};
 9     int m[N][N];
10     memset(m,0,sizeof(m));
11     int n=6,c=12;   //n,c均要小于N 
12     for(int i=1;i<=n;i++)
13     for(int j=1;j<=c;j++)
14     {
15         if(j>=w[i])
16         {
17             m[i][j]=max(m[i-1][j],m[i-1][j-w[i]]+v[i]);
18         }
19         else
20         {
21             m[i][j]=m[i-1][j];
22         }
23     }
24     cout<<m[n][c]<<endl; //从前往后
25  
26     /*
27     for(int i=n;i>=1;i--)
28     for(int j=1;j<=c;j++)
29     {
30         if(j>=w[i])
31         {
32             m[i][j]=max(m[i+1][j],m[i+1][j-w[i]]+v[i]);
33         }
34         else
35         {
36             m[i][j]=m[i+1][j];
37         }
38     }
39     cout<<m[1][c]<<endl;//从后往前
40     */
41     return 0;
42 }

二、回溯法

 1进入左子树条件:cw+w[i]<=c   //cw为当前重量

 2进入右子树条件(减枝函数):cp+r>bestp   //cp为当前价值,bestp为当前最优价值,r为当前剩余物品价值总和。cp+r由函数     Bound计算。

 3需要先将物品按单位重量价值从大到小排序,按序进入左子树;进入右子树时,由函数Bound计算当前节点上界,只有其上界大于当前最优价值bestp时,才进入右子树,否则减去。

算法:

 1 void Backtrack(int i)
 2 {
 3     if(i>n)  //到达叶节点
 4     {
 5         bestp=cp; 
 6         return;
 7     }
 8     if(cw+w[i]<=c)  //进入左子树
 9     {
10         cw+=w[i];
11         cp+=v[i];
12         Backtrack(i+1);
13         cw-=w[i];
14         cp-=v[i];
15     }
16     if(Bound(i+1)>bestp)  //进入右子树
17     {
18         Backtrack(i+1);
19     }
20 } 
21  
22 int Bound(int i)  //计算上界
23 {
24     int cleft=c-cw;
25     int b=cp;          
26     while(i<=n&&w[i]<=cleft)  //以物品单位重量价值递减序装入物品
27     {
28         cleft-=w[i];
29         b+=v[i];
30         i++;
31     }
32     if(i<=n)//装满背包
33     {
34         b+=v[i]*(cleft/w[i]);
35     }
36     return b;
37 }

例子代码:

 1 #include<iostream>
 2 #define N 20
 3 using namespace std;
 4 int w[N]={0,4,6,2,2,5,1},v[N]={0,8,10,6,3,7,2};
 5 int n=6,c=12;
 6 int cp=0,cw=0,bestp=0;
 7 int Bound(int i)  //计算上界
 8 {
 9     int cleft=c-cw;
10     int b=cp;          
11     while(i<=n&&w[i]<=cleft)  //以物品单位重量价值递减序装入物品
12     {
13         cleft-=w[i];
14         b+=v[i];
15         i++;
16     }
17     if(i<=n)//装满背包
18     {
19         b+=v[i]*(cleft/w[i]);
20     }
21     return b;
22 }
23 void Backtrack(int i)
24 {
25     if(i>n)  //到达叶节点 
26     {
27         bestp=cp; 
28         return;
29     }
30     if(cw+w[i]<=c)  //进入左子树
31     {
32         cw+=w[i];
33         cp+=v[i];
34         Backtrack(i+1);
35         cw-=w[i];
36         cp-=v[i];
37     }
38     if(Bound(i+1)>bestp)  //进入右子树 
39     {
40         Backtrack(i+1);
41     }
42 } 
43  
44 int main()
45 {
46     Backtrack(1);
47     cout<<bestp<<endl;
48     return 0;
49 }

 

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/155389.html原文链接:https://javaforall.net

(0)
全栈程序员-站长的头像全栈程序员-站长


相关推荐

  • spring与quartz的整合[通俗易懂]

    spring与quartz的整合[通俗易懂]使用方法quartz是一个强大的任务调度框架,利用spring将其整合,添加较少的配置即可快速使用,主要步骤如下:0.导入需要的jar包或添加依赖,主要有spring-context-suppo

    2022年7月4日
    28
  • jdbc sql拼接字符串[通俗易懂]

    jdbc sql拼接字符串[通俗易懂]Listlist=this.getJtN().queryForList( "selectcpdmdm,cpmcmcfromt_cpxxwhere zt_dm=’1’andcpdmin("+cp_dm+")orderbydm");这样写是错误的,‘’单引号表示字符串,“”双引号表示字符串拼接,所以应改为"selectcpdmdm,cpmcmcfro…

    2022年6月29日
    25
  • 5G/NR SSB学习总结[通俗易懂]

    5G/NR SSB学习总结[通俗易懂]6.1SSB概念同步信号和PBCH块(SynchronizationSignalandPBCHblock,简称SSB),它由主同步信号(PrimarySynchronizationSignals,简称PSS)、辅同步信号(SecondarySynchronizationSignals,简称SSS)、PBCH三部分共同组成。6.2SSB特征…

    2022年6月30日
    36
  • rime android汉字,Rime输入法

    rime android汉字,Rime输入法Rime输入法的安卓版又叫同文输入法,是Rime输入法好几个版本中的一个,适合喜欢调校的人。界面比较简洁,也很小巧,功能就是输入,偏英文输入,支持调整颜色更改外观。Rime输入法简介RIME/中州韻輸入法引擎,是一個跨平臺的輸入法算法框架。基於這一框架,Rime開發者與其他開源社區的參與者在Windows、MacOSX、Linux、Android平臺上創造了不同的輸入法前端實現。Rime…

    2022年7月12日
    32
  • 2021 goland mac 激活码-激活码分享[通俗易懂]

    (2021 goland mac 激活码)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年3月20日
    594
  • clion2022.01.4激活码【中文破解版】2022.03.07

    (clion2022.01.4激活码)本文适用于JetBrains家族所有ide,包括IntelliJidea,phpstorm,webstorm,pycharm,datagrip等。IntelliJ2021最新激活注册码,破解教程可免费永久激活,亲测有效,下面是详细链接哦~https://javaforall.net/100143.html…

    2022年4月2日
    236

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号