背包问题整理

一:01背包

有 NN 件物品和一个容量是 VV 的背包。每件物品只能使用一次。

第 ii 件物品的体积是 vivi,价值是 wiwi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,NVN,V,用空格隔开,分别表示物品数量和背包容积。

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 件物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V10000<N,V≤1000
0<vi,wi10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

8

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int a[N], b[N];
 7 //int dp[N];
 8 int n, v;
 9 
10 vector<vector<int>> memo(N, vector<int>(N, -1));
11 
12 int dfs(int i, int j){
13     if(memo[i][j] != -1) return memo[i][j];
14     if(i == 0) return memo[i][j] = 0;
15     int dfs1 = dfs(i-1, j);
16     int dfs2 = -1;
17     if(j >= a[i]) dfs2 = dfs(i-1, j - a[i]) + b[i];
18     return memo[i][j] = max(dfs1, dfs2);
19 }
20 
21 int main(){
22     cin >> n >> v;
23     for(int i = 1;i <= n;++i) cin >> a[i] >> b[i];//v p
24     /*
25     for(int i = 1;i <= n;++i)
26         for(int j = v;j >= a[i];--j)
27             dp[j] = max(dp[j], dp[j-a[i]] + b[i]);//核心,第i层状态由第i-1层状态得到
28     */    
29     cout << dfs(n, v) << endl;
30     return 0;    
31 }
View Code

二:完全背包

有 NN 种物品和一个容量是 VV 的背包,每种物品都有无限件可用。

第 ii 种物品的体积是 vivi,价值是 wiwi。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。
输出最大价值。

输入格式

第一行两个整数,NVN,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 NN 行,每行两个整数 vi,wivi,wi,用空格隔开,分别表示第 ii 种物品的体积和价值。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V10000<N,V≤1000
0<vi,wi10000<vi,wi≤1000

输入样例

4 5
1 2
2 4
3 4
4 5

输出样例:

10


 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int dp[N];
 7 int n, v;
 8 
 9 int w[N], p[N];
10 
11 int main(){
12     cin >> n >> v;
13     for(int i = 1;i <= n;++i) cin >> w[i] >> p[i];
14 
15     for(int i = 1;i <= n;++i)
16         for(int j = w[i];j <= v;++j)
17             //max后的dp[j]表示的是第i-1层的值,dp[j-w[i]]表示的是当前第i层如果要选k个物品由选k-1个物品更新得到
18             dp[j] = max(dp[j], dp[j-w[i]] + p[i]);
19     cout << dp[v] << endl;
20     return 0;
21 }
View Code

三:多重背包(未优化)

有 NN 种物品和一个容量是 VV 的背包。

第 ii 种物品最多有 sisi 件,每件体积是 vivi,价值是 wiwi。

求解将哪些物品装入背包,可使物品体积总和不超过背包容量,且价值总和最大。
输出最大价值。

输入格式

第一行两个整数,NVN,V,用空格隔开,分别表示物品种数和背包容积。

接下来有 NN 行,每行三个整数 vi,wi,sivi,wi,si,用空格隔开,分别表示第 ii 种物品的体积、价值和数量。

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V1000<N,V≤100
0<vi,wi,si1000<vi,wi,si≤100

输入样例

4 5
1 2 3
2 4 1
3 4 3
4 5 2

输出样例:

10


 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1010;
 5 
 6 int dp[N];
 7 int n, v;
 8 
 9 int w[N], p[N], s[N];
10 
11 int main(){
12     cin >> n >> v;
13     for(int i = 1;i <= n;++i) cin >> w[i] >> p[i] >> s[i];
14     
15     for(int i = 1;i <= n;++i){
16         for(int j = v;j >= 0;--j){
17             int t = 0;
18             while(t <= s[i] && j >= t * w[i]){
19                 dp[j] = max(dp[j], dp[j - t*w[i]] +  t*p[i]);
20                 ++t;
21             }
22         }
23     }
24                 
25     cout << dp[v] << endl;
26     return 0;
27 }
View Code

四:多重背包(二进制优化)

 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 1000*2000;
 5 
 6 int n, v;
 7 int dp[N], w[N], p[N];
 8 
 9 int main(){
10     cin >> n >> v;
11     //拆分
12     int cnt = 0;
13     for(int i = 1;i <= n;++i){
14         int a, b, sum; cin >> a >> b >> sum;
15         int k = 1;
16         while(k <= sum){
17             ++cnt;
18             w[cnt] = a*k;
19             p[cnt] = b*k;
20             sum -= k;
21             k *= 2;
22         }
23         if(sum){
24             ++cnt;
25             w[cnt] = a*sum;
26             p[cnt] = b*sum;
27         }
28     }    
29     //按照01背包问题求解
30     for(int i = 1;i <= cnt;++i)
31         for(int j = v;j >= w[i];--j)
32             dp[j] = max(dp[j], dp[j-w[i]]+p[i]);
33     
34     cout << dp[v] << endl;
35     return 0;
36 }
View Code

五:分组背包:

有 NN 组物品和一个容量是 VV 的背包。

每组物品有若干个,同一组内的物品最多只能选一个。
每件物品的体积是 vijvij,价值是 wijwij,其中 ii 是组号,jj 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

输出最大价值。

输入格式

第一行有两个整数 NVN,V,用空格隔开,分别表示物品组数和背包容量。

接下来有 NN 组数据:

  • 每组数据第一行有一个整数 SiSi,表示第 ii 个物品组的物品数量;
  • 每组数据接下来有 SiSi 行,每行有两个整数 vij,wijvij,wij,用空格隔开,分别表示第 ii 个物品组的第 jj 个物品的体积和价值;

输出格式

输出一个整数,表示最大价值。

数据范围

0<N,V1000<N,V≤100
0<Si1000<Si≤100
0<vij,wij1000<vij,wij≤100

输入样例

3 5
2
1 2
2 4
1
3 4
1
4 5

输出样例:

8

 1 #include <iostream>
 2 using namespace std;
 3 
 4 const int N = 110;
 5 int v[N][N], w[N][N];
 6 int s[N];
 7 int dp[N];
 8 
 9 int main(){
10     int n, m; cin >> n >> m;
11     for(int i = 1;i <= n;++i){
12         cin >> s[i];       
13         for(int j = 1;j <= s[i];++j)
14             cin >> v[i][j] >> w[i][j];
15     }
16     
17     for(int i = 1;i <= n;++i)
18         for(int j = m;j >= 0;--j)
19             for(int k = 1;k <= s[i];++k)
20                 if(j >= v[i][k])
21                     dp[j] = max(dp[j], dp[j - v[i][k]] + w[i][k]);
22     
23     cout << dp[m] << endl;
24     return 0;
25 }
View Code

end

原文地址:https://www.cnblogs.com/sxq-study/p/12298739.html