Report of the knapsack algorithm(4 types)
1.1
//knapsack,
/question: 有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是vi。求解将哪些物品装入背包可使价值总和最大。/
#include<iostream>
#include<algorithm>
#include<cstring>
#define MAXN 100
using namespace std;
int ci[MAXN],vi[MAXN];
int dp[MAXN][MAXN]; //全局变量自动赋值为0
int main()
{
int N,V;
cin>>N>>V;
for(int i=1;i<=N;i++)
{
cin>>ci[i]>>vi[i];
}
for(int i=1;i<=N;i++)//从第一个物品开始求解
{
for(int j=0;j<=V;j++)//循环容量
{
dp[i][j]=dp[i-1][j];//即使是没有大于当前的容量花费,但是作为打表传递,前面的容量的的位置也要传递过来
if(j>=ci[i])
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-ci[i]]+vi[i]);
}
}
}
cout<<dp[N][V];//因为有传递的效果,所以最后结尾的最大值一定为全局的最优解
return 0;
}
输入测试样本:
5 10 N V
5 6 cost value
5 7
2 8
8 1
5 9
输出结果:17 //下面为打表测试,横坐标为容量,纵坐标为物品数量值
1.2 上述空间仍然可以改进,可以缩小为一维数组此时算法时间复杂度为O(nV),空间复杂度为O(V),
//01knapsack,
/question: 有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是vi。求解将哪些物品装入背包可使价值总和最大。/
//改进算法,缩小空间
#include<iostream>
#include<algorithm>
#include<cstring>
#define MAXN 100
using namespace std;
int ci[MAXN],vi[MAXN];
int dp[MAXN]; //全局变量自动赋值为0
int main()
{
int N,V;
cin>>N>>V;
for(int i=1;i<=N;i++)
{
cin>>ci[i]>>vi[i];
}
for(int i=1;i<=N;i++)//从第一个物品开始求解 //对于dp[i][],每次只需要用到dp[i-1][];故可以考虑直接存在一维数组中
{
for(int j=V;j>=ci[i];j--)//循环容量 但是一维的数组则需要从右向左循环,因为前面的数据会被覆盖
{
dp[j]=max(dp[j],dp[j-ci[i]]+vi[i]);
}
}
cout<<dp[V];//因为有传递的效果,所以最后结尾的最大值一定为全局的最优解
return 0;
}
同上述数据:
结果相同
- 在上述的基础上要求恰好满包
//01knapsack,
/question: 有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是vi。求解将哪些物品装入背包可使价值总和最大。/
//现在要求为满包情况,即刚好将背包塞满
#include<iostream>
#include<algorithm>
#include<cstring>
#define MAXN 100
#define NINF 1<<31
using namespace std;
int ci[MAXN],vi[MAXN];
int main()
{
//int M;
//cin>>M;
//int record[MAXN];
//int k=0;
int N,V;
cin>>N>>V;
int dp[MAXN]; //除了dp[0]为0之外其他的均为负无穷
//while(M--)
//{
for(int i=1;i<=V;i++)
{
dp[i]=NINF; //除了容量为0其他的容量下,价值均为无穷小
}
dp[0]=0;//dp[0]即容量为0 时,价值为0
for(int i=1;i<=N;i++)
{
cin>>ci[i]>>vi[i];
}
for(int i=1;i<=N;i++)//从第一个物品开始求解 //对于dp[i][],每次只需要用到dp[i-1][];故可以考虑直接存在一维数组中
{
for(int j=V;j>=ci[i];j--)//循环容量 但是一维的数组则需要从右向左循环,因为前面的数据会被覆盖
{
dp[j]=max(dp[j],dp[j-ci[i]]+vi[i]);
}
}
if(dp[V]<0) dp[V]=0; // 当为无穷小时,则赋值为0
// record[k++]=dp[V];
cout<<dp[V];//dp[x]即容量为x时的最大值,恰好装满。即容量为V 时的值
// }
// for(int i=0;i<k;i++)
// {
// cout<<record[i]<<endl;
//}
return 0;
}
样例:
输出结果:
3.在1的基础上,背包中最多放m个物品,求其最大值
//01knapsack,
/question: 有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是vi。求解将哪些物品装入背包可使价值总和最大。/
//背包中最多放m件物品
#include<iostream>
#include<algorithm>
#include<cstring>
#define MAXN 100
using namespace std;
int ci[MAXN],vi[MAXN];
int dp[MAXN][MAXN]; //全局变量自动赋值为0
int k[MAXN][MAXN]; //记录每个表的位置时其已经选了的个数。
int main()
{
int N,V;
int m;//增加约束:最多放m件物品
cin>>N>>V;
cin>>m;
for(int i=1;i<=N;i++)
{
cin>>ci[i]>>vi[i];
}
for(int i=1;i<=N;i++)//从第一个物品开始求解
{
for(int j=0;j<=V;j++)//循环容量
{
dp[i][j]=dp[i-1][j];//即使是没有大于当前的容量花费,但是作为打表传递,前面的容量的的位置也要传递过来
if(j>=ci[i])
{
dp[i][j]=max(dp[i-1][j],dp[i-1][j-ci[i]]+vi[i]);
}
///
if(dp[i][j] != dp[i-1][j])//如果当前第i件最大值不等于第i-1件,则表明加入了第i件,K+1;
{
k[i][j]=k[i-1][j-ci[i]]+1;
}
else{
k[i][j]=k[i-1][j];
}
}
}
for(int i=1;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
cout<<dp[i][j]<<' ';
}
cout<<endl;
}
cout<<endl;
/
for(int i=1;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
cout<<k[i][j]<<' ';
}
cout<<endl;
}
cout<<endl;
int maxn=dp[0][0];
for(int i=1;i<=N;i++)
{
for(int j=0;j<=V;j++)
{
if(maxn<dp[i][j] && k[i][j]<=m)
{
swap(maxn,dp[i][j]);
}
}
}
cout<<maxn;
return 0;
}
//核心思想,再利用一个二维数组记录当前所在位置已经加入了几个数,也通过递推关系求
//也可以将两者均化为一维数组,类似上述1.2
输入数据:
5 10 1 物品数 背包容量 最多m个
5 6 花费 价值
5 7
2 8
8 1
5 9
输出结果:
输入数据:
5 10 2 物品数 背包容量 最多m个
5 6 花费 价值
5 7
2 8
8 1
5 9
输出结果:
4.在1的基础上,分为两个背包存储,求解最大值
//01knapsack,
/question: 有N件物品和一个容量为V 的背包。放入第i件物品耗费的空间是Ci,得到的价值是vi。求解将哪些物品装入背包可使价值总和最大。/
//现在分为2个背包V1 , V2
//利用二维数组DP,但是此时的二维中没有个数i,而是利用V1 V2进行递推
#include<iostream>
#include<algorithm>
#include<cstring>
#define MAXN 100
using namespace std;
int ci[MAXN],vi[MAXN];
int dp[MAXN][MAXN]; //全局变量自动赋值为0
int main()
{
int N,V1,V2;
cin>>N>>V1>>V2;
//int res=0;
for(int i=1;i<=N;i++)
{
cin>>ci[i]>>vi[i];
}
for(int i=1;i<=N;i++)//从第一个物品开始求解 //实则是1.2的改编,1.2将dp降到了一维,只要循环容量V,此处将容量V1,V2弄成二维进行递推
{
for(int j=V1;j>=0;j--)//循环容量 ci[i]
{
for(int k=V2;k>=0;k--)
{
if(j>=ci[i] && k>=ci[i])
{
dp[j][k]=max(dp[j][k],max(dp[j-ci[i]][k]+vi[i],dp[j][k-ci[i]]+vi[i])) ;
}else if(j>=ci[i])
{
dp[j][k]=max(dp[j][k],dp[j-ci[i]][k]+vi[i]);
}else if(k>=ci[i])
{
dp[j][k]=max(dp[j][k],dp[j][k-ci[i]]+vi[i]);
}
// if(res<dp[j][k])
// {
// res=dp[j][k];
// }
// dp[i][j]=dp[i-1][j];//即使是没有大于当前的容量花费,但是作为打表传递,前面的容量的的位置也要传递过来
//
// if(j>=ci[i])
// {
//
// dp[i][j]=max(dp[i-1][j],dp[i-1][j-ci[i]]+vi[i]);
// }
//
}
}
}
cout<<dp[V1][V2]<<endl;//因为有传递的效果,所以最后结尾的最大值一定为全局的最优解
//cout<<res<<endl;
return 0;
}
输入数据:
5 10 5 个数 第一个背包的大小 第二个背包的大小
5 6 花费 价值
5 7
2 8
8 1
5 9
输出结果: