ACwing动态规划
Wiretender动态规划(简单DP)


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> #include <cstdio> #include <cstring>
using namespace std; const int N = 1005;
int f[N][N], w[N][N];
void solve() { memset(f, 0, sizeof f); int r, c; cin >> r >> c; for(int i = 1;i <= r;i ++) for(int j = 1;j <= c;j ++) cin >> w[i][j]; f[1][1] = w[1][1]; for(int i = 1;i <= r;i ++) for(int j = 1;j <= c;j ++) f[i][j] = max(f[i - 1][j] + w[i][j], f[i][j - 1] + w[i][j]); cout << f[r][c] << endl; }
int main() { int _; cin >> _; while(_ --) solve(); 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60
| #include <cstring> #include <iostream> #include <cstdio> #include <algorithm>
using namespace std;
const int MOD = 1e9 + 7;
const int N = 52;
int n, m, k; int w[N][N], f[N][N][13][14];
int main() { cin >> n >> m >> k; for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) { cin >> w[i][j]; w[i][j] ++; } f[1][1][1][w[1][1]] = 1; f[1][1][0][0] = 1; for(int i = 1;i <= n;i ++) for(int j = 1;j <= m;j ++) { if(i == 1 && j == 1) continue; for(int u = 0; u <= k;u ++) for(int v = 0; v <= 13;v ++) { int &val = f[i][j][u][v]; val = (val + f[i - 1][j][u][v]) % MOD; val = (val + f[i][j - 1][u][v]) % MOD; if(u > 0 && v == w[i][j]) { for(int c = 0; c < v;c ++) { val = (val + f[i - 1][j][u - 1][c]) % MOD; val = (val + f[i][j - 1][u - 1][c]) % MOD; } } } } int res = 0; for(int i = 0;i <= 13;i ++) res = (res + f[n][m][k][i]) % MOD; cout << res << 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 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66
| #include <cstdio> #include <algorithm> #include <iostream> #include <cstring> using namespace std; using ll = long long; const int N = 110;
int n, m; int v[N], w[N * 10], c[N]; int f[N];
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];
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 28 29 30
| #include <cstdio> #include <cstring> #include <iostream> #include <algorithm>
using namespace std;
const int N = 1010;
int n, m; int v[N], w[N]; 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 <= m;i ++) f[0][i] = 0;
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 - v[i]] + w[i], f[i][j]); } cout << f[n][m]; return 0; }
|
分组背包问题

- 思路:按照y总的模板来

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
| #include <iostream> #include <algorithm> #include <cstdio> #include <cstring>
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]; 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
| #include <iostream> #include <algorithm> #include <cstdio> #include <cstring>
using namespace std; const int N = 1010; const int p = 1e9 + 7;
int f[N][N];
int main() { int n; cin >> n; for(int i = 1;i <= n;i ++) f[i][0] = 1; for(int i = 1;i <= n;i ++) for(int j = 1;j <= n;j ++) { f[i][j] = f[i - 1][j]; if(j >= i) f[i][j] = (f[i][j - i] + f[i][j]) % p; } cout << f[n][n] << 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
| #include <iostream> #include <algorithm> #include <cstdio> #include <cstring>
using namespace std; const int N = 1010; const int p = 1e9 + 7;
int f[N];
int main() { int n; cin >> n; f[0] = 1; for(int i = 1;i <= n;i ++) for(int j = i;j <= n;j ++) { f[j] = (f[j - i] + f[j]) % p; } cout << f[n] << endl; return 0; }
|
- 总结:和无穷背包的优化思路一致,可以看作无穷背包来进行思考
划分问题2(01背包)

根据01背包和无穷背包的区别,直接改个循环顺序直接秒了
原因:01背包是从上一层的状态转移过来,所以我们需要倒序遍历,这样可以保证我们之前的状态时被更新过的,而不是正序遍历造成重复遍历
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| #include <iostream> #include <algorithm> #include <cstdio> #include <cstring>
using namespace std; const int N = 1010; const int p = 1e9 + 7;
int f[N];
int main() { int n; cin >> n; f[0] = 1; for(int i = 1;i <= n;i ++) for(int j = n;j >= i;j --) { f[j] = (f[j - i] + f[j]) % p; } cout << f[n] << endl; return 0; }
|

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
| #include <iostream> using namespace std; using ll = long long; ll f[2023][11][2023];
int main() { for(int i = 0;i <= 2022;i ++) f[i][0][0] = 1; for(int i = 1;i <= 2022;i ++) for(int j = 1;j <= 10;j ++) for(int k = 1;k <= 2022;k ++) { f[i][j][k] = f[i - 1][j][k]; if(k >= i) f[i][j][k] += f[i - 1][j - 1][k - i]; }
cout << f[2022][10][2022]; return 0; }
|