有 N 种物品和一个容量是 V 的背包,每种物品都有无限件可用。
第 ii 种物品的体积是 vi,价值是 wi。
求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。
输入格式
第一行两个整数,N,V用空格隔开,分别表示物品种数和背包容积。
接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。
输出格式
输出一个整数,表示最大价值。
数据范围
0<N,V≤1000
0<vi,wi≤1000
输入样例
4 5
1 2
2 4
3 4
4 5
输出样例:
10
表示在前 i 个物品中,第 i 个物品选了k个
k = 0时 , f [ i -1 ] [ j ]
k = k时 , f[ i - 1 ] [ j - k * v [ i ] ] + k * w [ i ]
未优化前, 超时
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int f[N][N] , v[N] ,w[N] ;
int n , m ;
int main()
{
cin >> n >> m ;
for( int i = 1 ;i <= n ; i++ ) cin>> v[i] >> w[i] ;
for(int i = 1 ; i <= n ; i++ ){
for(int j = 0 ; j <= m ; j++ ){
for(int k = 0 ; k * v[i] <= j ; k ++){
f[i][j] = max( f[i][j] , f[i-1][j -k*v[i] ] + k* w[i] );
}
}
}
cout << f[n][m] <<endl ;
return 0;
}
优化:
f [ i ] [ j ] = max ( f [ i -1 ] [ j ] , f [ i - 1] [ j - v [ i ] ] + w [ i ] , f [ i - 1] [ j - 2 * v [ i ] ] + 2 * w [ i ] , f [ i - 1] [ j - 3 * v [ i ] ] + 3 * w [ i ] ...... ) (1)
f [ i ] [ j - v [ i ] ] = max ( f [ i -1 ] [ j - v [ i ] ] , f [ i - 1] [ j - 2 * v [ i ] ] + w [ i ] , f [ i - 1] [ j - 3 * v [ i ] ] + 2 * w [ i ] ...... ) (2)
对比以上, (2)式子的每一项都比(1)的多了一个w[ i ] , 所以只要(2)每一项加上w[ i ] 就等于(1)中除黑色之外的部分 即{f [ i - 1] [ j - v [ i ] ] + w [ i ] , f [ i - 1] [ j - 2 * v [ i ] ] + 2 * w [ i ] , f [ i - 1] [ j - 3 * v [ i ] ] + 3 * w [ i ] ...... },而(2)式子的结果等于f [ i ] [ j - v [ i ] ] + w [ i ] ,所以(1)式子等于 f [ i ] [ j ] = max ( f [ i -1 ] [ j ] , f [ i ] [ j - v [ i ] ] + w[ i ] )
优化为二维
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int f[N][N] , v[N] ,w[N] ;
int n , m ;
int main()
{
cin >> n >> m ;
for( int i = 1 ;i <= n ; i++ ) cin>> v[i] >> w[i] ;
for(int i = 1 ; i <= n ; i++ ){
for(int j = 0 ; j <= m ; j++ ){
f[i][j] = f[i-1][j];
if( j >= v[i]) f[i][j] = max( f[i][j] , f[i][j-v[i]] + w[i] );
}
}
cout << f[n][m] <<endl ;
return 0;
}
回顾01背包与完全背包的代码,极度相似。
f [ i ] [ j ] = f [ i -1 ] [ j ] 中,计算f [ i ] [ j ] 时,f [ i - 1 ] [ j ] 为上一轮中的值,而去掉第一维后在计算本轮之前,f [ j ] 为上一轮的值,与未去掉一维之前f [ i -1] [ j ]一致,故 f [ j ] = f [ j ] ,式子为等价 可直接舍去
f [ i ] [ j ] = max( f [ i ] [ j ] , f [ i ] [ j - v [ i ] ] + w [ i ] ) 第一维都为 i ,计算时使用的是本轮已经计算好的值,所以不用类似于01背包时逆序求值 , 直接从前往后计算
优化为一维
#include <iostream>
#include <cstring>
#include <algorithm>
using namespace std;
const int N = 1010;
int f[N] , v[N] ,w[N] ;
int n , m ;
int main()
{
cin >> n >> m ;
for( int i = 1 ;i <= n ; i++ ) cin>> v[i] >> w[i] ;
for(int i = 1 ; i <= n ; i++ ){
for(int j = v[i] ; j <= m ; j++ ){
f[j] = max( f[j] , f[j -v[i] ] + w[i] );
}
}
cout << f[m] <<endl ;
return 0;
}