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


| 12
 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;
 }
 
 | 

| 12
 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;
 }
 
 
 | 
多重背包二进制优化
| 12
 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;
 }
 
 | 
无穷背包解法
| 12
 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总的模板来
 
| 12
 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;
 }
 
 | 
划分问题(无穷背包)
| 12
 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;
 }
 
 | 
优化:
| 12
 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背包是从上一层的状态转移过来,所以我们需要倒序遍历,这样可以保证我们之前的状态时被更新过的,而不是正序遍历造成重复遍历
| 12
 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;
 }
 
 | 

| 12
 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;
 }
 
 |