背包模型
前言
对于原始背包问题及其优化可以参见这篇博客
背包问题
背包问题的初始化问题
一般问题有以下三种情况
对应的初始化方法
- 对于体积最多是j, f [ 0 ] [ j ] f[0][j] f[0][j]表示一个物品都不选体积最多是j的情况,这个是存在的,所以置为0 ,对于循环中我们是最多是j,如果 v < 0 ,说明 v1 > j ,这是不存在的。
- 对于体积恰好是j, f [ 0 ] [ j ] f[0][j] f[0][j]表示一个物品都不选体积最多是j的情况,只有 f [ 0 ] [ 0 ] f[0][0] f[0][0]是存在的,其余的都是这个是不存在的,因此设置为一个不合法的数,至于是正无穷还是负无穷,取决于题目是求最大还是最小;对于循环边界理由和上面一样
- 对于初始化条件与第2个一样 ;对于循环条件,我们·是至少是j因此当v<0的时候是存在的,而它们的值是 v = 0 时候的值。
01背包
装箱问题
个人解题思路:
这题是让我们尽可能的让背包的剩余空间小,也就是放入的物品的体积要尽可能的大,因为物品只给了体积没有价值,那么我们就可能将每一个物品的价值等同于它的体积,那么这就转变为了01背包问题。那么这个 d p [ i ] dp[i] dp[i]表示总体积不超过背包容量下的最大体积,也就说剩余体积最小。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 35 , M = 20010;
int n , m ;
int w[N] , v[N] ,f[M];
int main(){
cin>>m>>n;
for(int i = 1 ; i <= n ; ++i)cin>>w[i] ;
for(int i = 1; i <= n ; ++i)
for(int j = m ; j >= w[i] ; --j)
f[j] = max(f[j] , f[j-w[i]] + w[i]);
cout<<m - f[m]<<endl;
return 0;
}
宠物小精灵之收服
解题思路:
这题由单一花费变成了二维花费,我们的花费有精灵球的数量和体力,因此我们定义的是二维dp; d p [ i ] [ j ] [ k ] dp[i][j][k] dp[i][j][k]表示考虑前i个精灵,精灵球数量不超过j,体力不超过k的最大的精灵球数量。由背包问题我们可以将第一维的空间省略掉,采用逆序的遍历方式。对于二维我们还是有
对于剩余的体力,我们在 f [ N ] [ 1 − M ] f[N][1-M] f[N][1−M]中选出等于 f [ N ] [ M ] f[N][M] f[N][M]的最小的体力,这是花费的最小体力。同时因为体力不能会0,我们再减1.
代码:
#include<iostream>
#include<algorithm>
#include<cstring>
using namespace std;
const int N = 110 , M = 1010;
int n , m , K;
int w[N] , v[N] ,f[M][M] ;
int main(){
cin>>m>>K>>n;
for(int i = 1; i <= n ; ++i)cin>>w[i]>>v[i];
for(int i = 1 ; i <= n ; ++i)
for(int j = m ; j >= w[i]; --j)
for(int k = K ; k > v[i] ; --k )
f[j][k] = max(f[j][k] ,f[j-w[i]][k-v[i]] + 1);
cout<<f[m][K]<<' ';
int cnt = 0;
for(int k = 1 ; k <= K ; ++k)
if(f[m][k] == f[m][K]){
cnt = k - 1;
break;
}
cout<<K - cnt <<endl;
return 0;
}
数字组合
解题思路;
这是一个典型的0/1背包模型,N个正整数就是N个物品,M就是背包的容积。在外层循环到i时(表示从前i个数中选),设F[j]表示“和为j”有多少种方案。在具体实现中,只需要把原始代码中求max的函数改为求和即可。
代码:
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 110 , M = 10010;
int n , m ;
int w[N] , f[M];
int main(){
cin>>n>>m;
for(int i = 1; i <= n ; ++i)cin>>w[i];
f[0] = 1;
for(int i = 1; i <= n ; ++i)
for(int j = m; j >= w[i] ; --j)
f[j] += f[j-w[i]];
cout<<f[m]<<endl;
return 0;
}
开心的金明
解题思路:
这题我们可以将每一个物品的钱看成是体积,而物品的价值则是金额*重要程度。这样我们就转化成了01背包问题了、
代码;
#include<iostream>
#include<algorithm>
using namespace std;
const int N = 50010;
int n , m;
int f[N];
int main