问题描述
现在有一个背包,这个背包的容积一定
- 但是现在有n个物品,每个物品都有对应的体积和价值
- 要求如何让操作才能够使得我们讲尽可能值钱的物品放到这个背包里面
解题思路与算法思想
- 当看到这道题的时候,我们很自然地会认为这是一个搜索问题
但是由于当n足够大的时候,这个搜索问题的复杂度令人发指
- 于是我们用动态规划问题来求这个方法
其实我们可以这个事情抽象成一个决策树
这个树一共有n层,每一层的代表你对放进去还是不放进去某件物品进行决策
这样就会最终得到2^N种结果
之后经过观察我们可以发现,我i们可以反向推到这个决策的过程
首先明确一点:
我们选择的结果和我们选择的顺序无关
那就就可以从这个树的最底层网上倒推
每一个第i行的树节点之和与相连的两个第i+1层的树节点相关,而最底层的树节点是我们可以事先规定的
那么就可以根据公式:f(i,j) = max(f(i+1,j),f(i+1,j-v[i])+w[i]) ;
对于你到底要不要把第i件物品放进去,这和你已经放进去的东西有关
程序模型的建运用
- 递推的思路去储存信息
- 重点运用好表达式
数据结构的选用
- 数组
核心算法
程序设计流程
-
输入
-
数据录入
-
进行选择
-
输出
程序设计伪码算法
for(int i= n-1 ;i>=0 ;i--)
{
for(int j = 0 ;j<sumV ;j++)
{
a[i][j] = a[i+1][j] ;
if(j>=V[i])
{
a[i][j] = max(a[i+1][j] , a[i+1][j-V[i]]+value[i]) ;
}
}
}
源程序编码清单
- `#include<iostream>
#include<algorithm>
#include<vector>
using namespace std ;
int main(void)
{
vector<int>V ;
vector<int>value ;
int sumV ;
scanf("%d",&sumV) ;//先输入背包的体积
int n ;
scanf("%d",&n) ;//输入物品的个数
int tem ;
for(int i = 0 ;i<n ;i++)
{
//输入先是体积,之后是价值
scanf("%d",&tem) ;
V.push_back(tem) ;
scanf("%d",&tem) ;
value.push_back(tem) ;
}
// 输入完成
//完成对于记忆数组的处理
vector< vector<int> >a ;//总的记忆数组
vector<int>b ;
for(int i = 0 ;i<sumV ;i++)
{
b.push_back(0) ;
}
for(int i = 0 ;i<=n ;i++)
{
a.push_back(b) ;
}
//cout<<a[0][0]<<endl ;
/*a.resize(n) ;
for(int i = 0 ;i<n ;i++)
{
a[i].resize(sumV) ;
} */
//先完成对于数组的初始化
for(int j = 0 ;j < sumV; j++)
{
a[n][j] = 0 ;//最底层的都是零(因为还没有开始选择)
}
//之后通过状态转移方程得出结论
for(int i= n-1 ;i>=0 ;i--)
{
for(int j = 0 ;j<sumV ;j++)
{
a[i][j] = a[i+1][j] ;
if(j>=V[i])
{
a[i][j] = max(a[i+1][j] , a[i+1][j-V[i]]+value[i]) ;
}
}
}
for(int i = 0 ;i<=n ;i++)
{
for(int j = 0 ;j<sumV ;j++)
{
printf("%d ",a[i][j]) ;
}
printf("\n") ;
}
int bb = 0 ;
for(int i = 0 ;i<sumV ;i++)
{
if(a[0][i]>bb)
{
bb = a[0][i] ;
}
}
printf("%d",bb) ;
// printf("%d",a[0][0]) ;
}`
程序输入、输出
输入:10 5
10 5
2 6
2 3
6 5
5 4
4 6
输出:
15
输入:输入输出文件,或程序运行结果截图
时间与空间复杂度分
N^2
程序使用说明
总结与完善