uboot常用命令
阿新 • • 發佈:2020-09-01
完全揹包:每一種物品可以選任意多次的揹包問題。
經過分析,可以在01揹包的程式碼基礎上,增加一層迴圈,有以下暴力程式碼\(O(n^3)\)
#include<iostream> using namespace std; const int N = 1010; int n, m; int w[N], v[N]; int f[N][N]; int main(){ cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i]; //f[0][1 ~ m] = 0; for(int i = 1; i <= n; i ++){ for(int j = 1; j <= m; j ++){ f[i][j] = f[i - 1][j]; int k = j / v[i]; for(int t = 1; t <= k; t ++) f[i][j] = max(f[i][j], f[i - 1][j - t * v[i]] + t * w[i]); } } cout << f[n][m]; return 0; }
時間上需要優化:
由上圖:
\(f(i, j) = max(f(i - 1, j), f(i - 1, j - v[i]), f(i - 1, j - 2 * v[i]), ... , f(i - 1, j - k * v[i]), ...)\)
做一個變數代換,將上式中的j換成\(j - v[i]\)
得\(f(i, j - v[i]) = max(f(i - 1, j - v[i]), f(i - 1, j - 2 * v[i]) ,...)\)
發現第一個式子中\(max(f(i - 1, j), 後面一坨)\)中 \(後面一坨 = max(f(i - 1, j), f(i - 1, j - v[i]), ...) = max(f(i - 1, j - v[i]), f(i - 1, j - 2 * v[i]), ...) + w[i] = f(i, j - v[i]) + w[i]\)
所以得到\(f(i, j) = max(f(i - 1, j), f(i, j - v[i]) + w[i])\)
所以就可以把上面得第三重迴圈優化成O(1)的了
#include<iostream> using namespace std; const int N = 1010; int n, m; int w[N], v[N]; int f[N][N]; int main(){ cin >> n >> m; for(int i = 1; i <= n; i ++) cin >> v[i] >> w[i]; //f[0][1 ~ m] = 0; for(int i = 1; i <= n; i ++){ for(int j = 1; 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]; return 0; }
最後通過程式碼等價變形的方法,把空間優化成1維
#include<iostream>
using namespace std;
const int N = 1010;
int n, m;
int w[N], v[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 = v[i]; j <= m; j ++)
f[j] = max(f[j], f[j - v[i]] + w[i]); // 此處正好需要的是第i層的f[j - v[i]],所以第二重迴圈不需要倒著來
cout << f[m];
return 0;
}