数据结构算法DP
Alive~o.0背包问题
背包九讲问题-dd大牛的《背包九讲》
0-1背包问题
有n 个物品,它们有各自的体积/重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
每件物品只有一个
思路

二维(朴素)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N][N];
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 - 1][j - v[i]]+ w[i]); } } cout << f[n][m] << endl; return 0; }
|
一维优化(滚动数组)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N];
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 = m;j >=v[i];j--){ f[j] = max(f[j],f[j - v[i]]+ w[i]); } } cout << f[m] << endl; return 0; }
|
极好的题解
完全背包问题
有n 个物品,它们有各自的体积/重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
每件物品有无限个
思路


朴素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N][N];
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; }
|
优化(简化内部关系)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N][N];
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]>=0) f[i][j]=max(f[i][j],f[i][j-v[i]]+w[i]); } } cout << f[n][m] << endl; return 0; }
|
一维优化
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N];
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++){ if(j-v[i]>=0) f[j]=max(f[j],f[j-v[i]]+w[i]); } cout << f[m] << endl; return 0; }
|
多重背包问题
有n 个物品,它们有各自的体积/重量和价值,现有给定容量的背包,如何让背包里装入的物品具有最大的价值总和?
每件物品有si个
思路

朴素
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n,m; int v[N]={0},w[N]={0}; int f[N][N],s[N];
int main() { cin >> n >> m; for(int i = 1;i <= n; i++) cin >> v[i] >> w[i] >> s[i]; for(int i = 1;i <= n ;i++){ for(int j = 0;j <= m;j++){ for(int k = 0;k*v[i] <= j && k <= s[i];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; }
|
优化(二进制优化、0-1背包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 25000,M=2010;
int n,m; int v[N]={0},w[N]={0}; int f[M];
int main() { cin >> n >> m; int cnt=0; for(int i = 1;i <= n; i++) { int a,b,s; cin >> a >> b >> s; int k=1; while(k<=s){ cnt++; v[cnt] = a*k; w[cnt] = b*k; s-=k; k *= 2; } if(s > 0) { cnt++; v[cnt] = a*s; w[cnt] = b*s; } } n = cnt; for(int i = 1;i <= n ;i++){ for(int j = m;j >= v[i];j--){ f[j] = max(f[j],f[j-v[i]] + w[i]); } } cout << f[m] << endl; return 0; }
|
分组背包问题
有 N 组物品和一个容量是 V 的背包。每组物品有若干个,同一组内的物品最多只能选一个。每件物品的体积是 vij,价值是 wij,其中 i 是组号,j 是组内编号。求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。
思路

优化(0-1背包)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32
| #include <iostream> #include <algorithm>
using namespace std;
const int N = 110;
int n,m; int v[N][N],w[N][N],s[N]; int f[N];
int main() { cin >> n >> m; for(int i = 1;i <= n;i++){ cin >> s[i]; for(int j = 0;j < s[i];j++){ cin >> v[i][j] >> w[i][j]; } } for (int i = 1; i <= n; ++i) for (int j = m; j >= 0; --j) for (int k = 0; k < s[i]; ++k) if (v[i][k] <= j) f[j] = max(f[j], f[j - v[i][k]] + w[i][k]); cout << f[m] << endl; return 0; }
|
线性DP