目录
背包问题
01背包
朴素做法
#include <iostream> #include <algorithm> using namespace std; const int N = 1010; int n, m; int v[N], w[N];//v 保存体积,w 保存价值 int f[N][N];//保存所有集合最值状态 int main() { cin >> n >> m; for (int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i]; for(int i = 0; i <= m; i++)//初始化,前 0 中物品中选择 { f[0][i] = 0; } for (int i = 1; i <= n; i ++ ) { for (int j = 1; j <= m; j ++) { if(v[i] <= j)//能放入第 i 件物品的情况下,求f[i][j] f[i][j] = max(f[i - 1][j], f[i - 1][j - v[i]] + w[i]); else//不能放入第 i 件物品的情况下,求f[i][j] f[i][j] = f[i - 1][j]; } } cout << f[n][m] << endl;//f[n][m] 就是答案 return 0; }
一维优化
#include <iostream> #include <algorithm> using namespace std; const int N = 1010; int n, m; int v[N], w[N]; 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; }
完全背包
朴素做法
#include<iostream> using namespace std; const int N = 1010; int n, m; int f[N][N], v[N], w[N]; int main(){ cin >> n >> m; for(int i = 1; i <= n; i ++ ) cin >> v[i] >> w[i]; for(int i = 0; i <= m; i++)//初始化 { f[0][i] = 0; } 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]);//求出每一个 f[i][j] cout << f[n][m] << endl; }
化简
*fi = max( fi-1 , fi-1 + w , fi-1 + 2 * w , fi-1 + 3 * w , .....)。* *fi = max( fi-1 , fi-1 + w , fi-1 + 2 * w , .....) 。*
由上两式,可得出如下递推关系: fi = max(fi + w , fi-1)
for(int i = 1; i <= n; i ++ ) { for(int j = 0; j <= m; j ++ ) { if(v[i] <= j)//第 i 种能放进去 f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]); else//如果第 i 件物品不能放进去 f[i][j] = f[i - 1][j]; } }
#include<iostream> using namespace std; const int N = 1010; int n, m; int f[N][N], v[N], w[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(v[i] <= j) f[i][j] =max(f[i - 1][j], f[i][j - v[i]] + w[i]);//优化 else f[i][j] = f[i - 1][j]; } } cout << f[n][m] << endl; }
一维优化
#include<iostream> using namespace std; const int N = 1010; int f[N]; int v[N],w[N]; int main() { int n,m; 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; }
多维背包
数据量小
#include <iostream> #include <vector> using namespace std; int main() { int N, V; cin >> N >> V; vector<vector<int>> dp(N + 1, vector<int>(V + 1, 0)); for (int i = 1; i <= N; ++i) { int vi, wi, si; cin >> vi >> wi >> si; for (int j = 1; j <= V; ++j) { for (int k = 0; k <= si && k * vi <= j; ++k) { dp[i][j] = max(dp[i][j], dp[i - 1][j - k * vi] + k * wi); } } } cout << dp[N][V] << endl; return 0; }
数据量大
优化图解(二进制优化)
#include <iostream> #include <algorithm> using namespace std; const int N = 12010, M = 2010; int n, m; int v[N], w[N]; 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; } //cout << cnt<<endl; } n = cnt; //当成01背包做了 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; }
分组背包
二维
#include <iostream> #include <cstring> #include <algorithm> using namespace std; const int N = 105; int s[N],v[N][N],w[N][N]; int f[N][N]; int main() { int n,m; cin >> n>>m; for (int i = 1; i <= n; i ++ ){ cin >> s[i]; for (int k = 1; k <= s[i]; k ++ ){ cin >> v[i][k]>>w[i][k]; } } for (int i = 1; i <= n; i ++ ){ for (int j = 0; j <= m; j ++ ){ //f[i][j]=f[i-1][j]; for (int k = 0; k <= s[i]; k ++ ){ if(v[i][k]<=j){ f[i][j]=max(f[i][j],f[i-1][j-v[i][k]]+w[i][k]); } } } } cout << f[n][m]; return 0; }
优化
#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 = 1;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(j >= v[i][k]){ f[j] = max(f[j],f[j - v[i][k]] + w[i][k]); } } } } cout<<f[m]<<endl; return 0; }