其他分享
首页 > 其他分享> > 背包九讲 整理中...

背包九讲 整理中...

作者:互联网

动态规划问题往往相当让人头疼,学习了Tianyi Cui大佬的背包九讲,做个整理。

一、01背包

题目:(题目取自AcWing,链接https://www.acwing.com/problem/content/2/

有 N 件物品和一个容量为 V 的背包。放入第 i 件物品耗费的费用是 Ci ,得到的 价值是 Wi。求解将哪些物品装入背包可使价值总和最大。

输入格式
  第一行两个整数,N,V,用空格隔开,分别表示物品数量和背包容积。
  接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 件物品的体积和价值。
输出格式
  输出一个整数,表示最大价值。
input:
4 5
1 2
2 4
3 4
4 5
output:
8

标准解法:

01背包就是要么装,要么不装,要求不高的题目用深搜回溯也能过了,对数据规模大的需要动态规划求解。

我们用f[i][j]表示前i个物品在背包容量为j下的最大价值,则对每个物品有两种情况,装或不装。若不装很好理解, f[i][j]=f[i-1][j]; 若装, f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+v[i]); 后一半是背包容量去掉当前物品大小然后加上当前物品价值。这里如果漏写与前一半的比较会出错,漏写往往是因为与回溯剪枝弄混了,这里的状态转移不是装了一定比不装价值大,一定要分清。

 

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 1005
 4 int f[maxn][maxn];//背包大小为i的最优解;
 5 int c[maxn];//费用
 6 int v[maxn];//价值
 7 int main()
 8 {
 9     int n,m;
10     cin>>n>>m;
11     for(int i=1; i<=n; i++)
12         cin>>c[i]>>v[i];
13     for(int i=1; i<=n; i++)
14         for(int j=1; j<=m; j++){
15             if(j<c[i])  f[i][j]=f[i-1][j];
16             else    f[i][j]=max(f[i-1][j],f[i-1][j-c[i]]+v[i]);
17         }
18     cout<<f[n][m];
19     return 0;
20 }

 

空间优化:

注意到标准解法的状态转移方程其实只与前一层的状态有关,由于解法自底向上的特性,我们只保留当前求解的前一层即可.

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 1005
 4 int f[maxn];//背包大小为i的最优解;
 5 int c[maxn];//费用
 6 int v[maxn];//价值
 7 int main()
 8 {
 9     int n,m;
10     cin>>n>>m;
11     for(int i=1; i<=n; i++)
12         cin>>c[i]>>v[i];
13     for(int i=1; i<=n; i++)
14         for(int j=m; j>=c[i]; j--)//1.这里逆序的原因是:用f[j]保存原来f[i-1][j]和f[i-1][j-c[i]]+v[i]的信息,要使前面的信息为i-1层的信息,必须后更新
15                                 //2.j>=c[i]的原因是:背包大小比c[i]小的显然不装,状态不变;另一个是f[j-c[i]]中的下标应不小于0
16             f[j]=max(f[j],f[j-c[i]]+v[i]);
17 
18     cout<<f[m];
19     return 0;
20 }

 

 二、完全背包

 题目:

有 N 种物品和一个容量为 V 的背包,每种物品都有无限件可用。放入第 i 种物品 的费用是 Ci,价值是 Wi。求解:将哪些物品装入背包,可使这些物品的价值总和最大。

输入格式
    第一行两个整数,N,V,用空格隔开,分别表示物品种数和背包容积。
    接下来有 N 行,每行两个整数 vi,wi,用空格隔开,分别表示第 i 种物品的体积和价值。
输出格式
    输出一个整数,表示最大价值。
input:
4 5
1 2
2 4
3 4
4 5
output:
10

解法一:

套用01背包的理论,完全背包就是每个物品可选数目为[0,V/wi];故 f[i][j]=max{f[i-1][j-kc[i]]+kv[i] | 0<=k<=V/c[i]} ,每次状态确定需要多花k步。可以先优化去掉大于V的物品以及c更大且v更小的物品

解法二:

还记得01背包空间优化的逆序原因吗,为了保证新状态的确定用的是前一层的状态,所以逆序更新。但完全背包正相反,新状态的确定需要一个能选到本层的状态,所以应该且必须用顺序更新。

 1 #include <bits/stdc++.h>
 2 using namespace std;
 3 #define maxn 1005
 4 int f[maxn];//背包大小为i的最优解;
 5 int c[maxn];//费用
 6 int v[maxn];//价值
 7 int main()
 8 {
 9     int n,m;
10     cin>>n>>m;
11     for(int i=1; i<=n; i++)
12         cin>>c[i]>>v[i];
13     for(int i=1; i<=n; i++)
14         for(int j=c[i]; j<=m; j++)//与01背包的空间优化仅是两者更新方向不同
15             f[j]=max(f[j],f[j-c[i]]+v[i]);
16 
17     cout<<f[m];
18     return 0;
19 }

 

 

 

  

 

标签:...,背包,九讲,int,maxn,物品,价值,解法
来源: https://www.cnblogs.com/better150/p/12248646.html