背包问题的求解
题目内容:
假设有一个能装入总体积为T的背包和n件体积分别为w1,w2,···,wn的物品,能否从n件物品中挑选若干件恰好装满背包,即使w1+w2+···+wm=T,要求找出所有满足上述条件的解。 例如,当T=10,各件物品的体积为{1,8,4,3,5,2}时,可找到下列4组解: (1,4,3,2) (1,4,5) (8,2) (3,5,2)
设计思想:
动态规划算法通常用于求解具有某种最优性质的问题。在这类问题中, 可能会有很多可行解。没一个解都对应于一个值,我们希望找到具有最优值的解。胎动规划算法与分治法类似,其基本思想也是将待求解问题分解为若干个子问题,先求解子问题,然后从这些子问题的解得到原问题的解。与分治法不同的是,适用于动态规划算法求解的问题,经分解得到的子问题往往不是互相独立的。若用分治法来解这类问题,则分解得到的子问题数目太多,有些子问题被重复计算很多次。如果我们能保存已解决子问题的答案,而在需要时再找出已求得的答案,这样就可以避免大量的重复计算,节省时间。我们可以用一个表来记录所有已解决的子问题的答案。不管该子问题以后是否被用到,只要它被计算过,就将其结果填入表中。这就是动态规划算法的基本思路。具体的动态规划算法多种多样,但它们具有相同的填表格式。
与分治法最大的差别是:适用于动态规划求解的问题,经分解后得到的子问题往往不是互相独立的(即下一个子阶段的求解是建立在上一个子阶段的解的基础上,进行进一步的求解)
递归实现背包问题的求解,挨个判断物体是否可以放进包内,背包装满后输出。
算法描述:
数组flag记录这个物品在不在包内,挨个判断物体是否可以放进包内,output为输出函数,按个判断,把标记为true的物品输出。递归时挨个判断,可以放入时,放入后递归时背包体积减小,递归结束后再将物品取出,标记为false。不可以放入后递归时背包体积不变。主程序输入背包体积和物品体积。
代码
#include <iostream>
#include <cstdio>
#include <cstring>
using namespace std;
int a[10000];
bool flag[10000];//标记
int T, n;
int c;
void output()//输出函数
{
c++;
for (int i = 0; i < n; i ++) {
if (flag[i])
cout<<a[i]<<" ";//物体在包内,输出
}
cout<<endl;
printf("\n");
}
void dfs(int V, int index) {
if (V == 0) {
output();//背包装满输出
return;
}
if (V < 0 || index >= n) {
return;//不和条件返回
}
dfs(V, index+1);//递归
if (V >= a[index]) {
flag[index] = true;//装进去为true
dfs(V - a[index], index+1);
flag[index] = false;//取出来为false
}
}
int main() {
cout<<"请输入背包体积的大小:"<<endl;
cin>>T;
cout<<"请输入物体个数:"<<endl;
cin>>n;
cout<<"请输入物体的体积:"<<endl;
for (int i = 0; i < n; i ++)
cin>>a[i];
memset(flag, false, sizeof(flag));//标记置为false
dfs(T, 0);//背包问题
return 0;
}
实验结果:
输入: 请输入背包体积的大小: 10 请输入物体个数: 6 请输入物体的体积: 1 8 4 3 5 2 输出: 3 5 2
8 2
1 4 5
1 4 3 2
体会与收获:
在考虑如何按顺序输出背包中物品时,可以用一个标记数组看这个东西是否在背包里,然后顺序判断输出。栈可以用递归取代。
建议与意见:
可以考虑如何避免再开一个数组记录物体是否在包中的同时还能将物品顺序输出。