问题分析
背包问题可以通过贪心、动态规划等多种算法解决实现。本文章从动态规划的角度求解0/1背包问题。动态规划原理:是一种将问题实例分解为更小的、相似的子问题,并存储子问题的解而避免计算重复的子问题,以解决最优化问题的算法方法。0/1背包问题本质上是寻找全局最优解的问题,在尽量消耗小的背包容量的前提下,获得更多的价值。
算法解析
①首先要对w(容积权重)和v(价值量)两个数组进行初始化,注意因为后面我们在进行动态规划求解时,需要考虑到前一个状态的解,因此这两个数组需要留出数组首位置防止越界。
for(int i=1;i<=thingNum;i++){
cin>>w[i]>>v[i];
}
②然后我们要计算出每个容量状态下的最优解作为子问题的解,以便我们求出想要的最优解。这里我们从前向后更新我们的dp数组,即得到每个容量状态的解。
void findMax(){
for(int i=1;i<=thingNum;i++){
for(int j=1;j<=bagContain;j++){
if(j<w[i]){
dp[i][j] = dp[i-1][j];//容量不够,仍为上一个状态的最优解
}
else if(dp[i-1][j]>(dp[i-1][j-w[i]]+v[i])){//更新后的解并不如上一个状态的解更优,解保持上一个状态的解
dp[i][j] = dp[i-1][j];
}
else{
//遇到更优的解就更新
dp[i][j] = (dp[i-1][j-w[i]]+v[i]);
}
}
}
}
③之后去寻找最优解的物品,从最大的问题开始,分解成更多的小问题,不断递归求解出小问题,最外层的最大问题便可以得出最终的最优解。
void findConsist(int thingNum,int bagContain){
if(thingNum>0){//没有分解为最小问题,继续递归
if(dp[thingNum-1][bagContain]==dp[thingNum][bagContain]||bagContain<w[thingNum]){
consist[thingNum]=0;//没有找到更优解或者背包的容量已经不够了,不要这件物品
findConsist(thingNum-1,bagContain);
}
else{
consist[thingNum] = 1;//找到更优解,将此物品加入背包
findConsist(thingNum-1,bagContain-w[thingNum]);
}
}
}
④结果展示:
完整代码
#include<iostream>
using namespace std;
int w[100]={0},v[100]={0},dp[100][100] = {0};
int thingNum,bagContain;//物品数量和背包容量
int consist[100]={0};
void findConsist(int thingNum,int bagContain){
if(thingNum>0){//没有分解为最小问题,继续递归
if(dp[thingNum-1][bagContain]==dp[thingNum][bagContain]||bagContain<w[thingNum]){
consist[thingNum]=0;//没有找到更优解或者背包的容量已经不够了,不要这件物品
findConsist(thingNum-1,bagContain);
}
else{
consist[thingNum] = 1;//找到更优解,将此物品加入背包
findConsist(thingNum-1,bagContain-w[thingNum]);
}
}
}
void findMax(){
for(int i=1;i<=thingNum;i++){
for(int j=1;j<=bagContain;j++){
if(j<w[i]){
dp[i][j] = dp[i-1][j];//容量不够,仍为上一个状态的最优解
}
else if(dp[i-1][j]>(dp[i-1][j-w[i]]+v[i])){//更新后的解并不如上一个状态的解更优,解保持上一个状态的解
dp[i][j] = dp[i-1][j];
}
else{
//遇到更优的解就更新
dp[i][j] = (dp[i-1][j-w[i]]+v[i]);
}
}
}
}
int main(){
cin>>thingNum>>bagContain;
for(int i=1;i<=thingNum;i++){
cin>>w[i]>>v[i];
}
findMax();
for(int i=0;i<=thingNum;i++){
for(int j=1;j<bagContain+1;j++){
cout<<dp[i][j]<<"\t";
}
cout<<endl;
}
findConsist(thingNum,bagContain);
for(int i=1;i<=thingNum;i++){
if(consist[i]==1){
cout<<i<<"号物品 ";
}
}
return 0;
}