目录

  • 数字三角形模型(只能向右和向下或向左和向上)
    • AcWing 1015. 摘花生
    • AcWing 1018. 最低通行费(曼哈顿距离-向右和向下-求最小值-初始化)
    • AcWing 1027. 方格取数
    • AcWing 275. 传纸条
  • 最长上升子序列模型
    • AcWing 1017. 怪盗基德的滑翔翼
    • AcWing 1014. 登山
    • AcWing 482. 合唱队形
    • AcWing 1012. 友好城市
    • AcWing 1016. 最大上升子序列和
    • AcWing 1010. 拦截导弹(贪心+stringstream语法)
    • AcWing 187. 导弹防御系统(dfs求最小步数)
    • AcWing 272. 最长公共上升子序列
  • 背包模型
    • 背包问题初始化总结
    • 一、01背包
      • AcWing 423. 采药
      • AcWing 1024. 装箱问题
      • AcWing 1022. 宠物小精灵之收服(二维体积)
      • AcWing 278. 数字组合(体积恰好,求总方案数)
      • AcWing 8. 二维费用的背包问题(二维体积)
      • AcWing 1020. 潜水员(二维体积,体积至少,最小价值)
      • AcWing 426. 开心的金明
      • AcWing 11. 背包问题求方案数(求最优选法的方案数)
      • AcWing 12. 背包问题求具体方案(打印方案)
      • AcWing 734. 能量石 (贪心)
    • 二、完全背包
      • AcWing 1023. 买书(体积恰好,求总方案数)
      • AcWing 1021. 货币系统(体积恰好,求总方案数)
      • AcWing 532. 货币系统(体积恰好,求总方案数)
    • 三、多重背包
      • AcWing 6. 多重背包问题 III
      • AcWing 1019. 庆功会
    • 四、分组背包
      • AcWing 1013. 机器分配(打印路径)
    • 五、混合背包
      • AcWing 7. 混合背包问题
    • 六、有依赖的背包问题
      • AcWing 10. 有依赖的背包问题
      • AcWing 487. 金明的预算方案

数字三角形模型(只能向右和向下或向左和向上)

AcWing 1015. 摘花生

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 110;int f[N][N];
int g[N][N];int main()
{int _; cin >> _;while (_ -- ){int r, c;cin >> r >> c;for (int i = 1; i <= r; i ++ )for (int j = 1; j <= c; j ++ )cin >> g[i][j];for (int i = 1; i <= r; i ++ )for (int j = 1; j <= c; j ++ ){f[i][j] = max(f[i - 1][j], f[i][j - 1]) + g[i][j];}cout << f[r][c] << endl;}return 0;
}

AcWing 1018. 最低通行费(曼哈顿距离-向右和向下-求最小值-初始化)

  • 四相邻,因此在矩阵中找任意两点的距离,用的不是欧氏距离d=x1−x22+y1−y22d=\sqrt{{x1-x2}^2+{y1-y2}^2}d=x1−x22+y1−y22​,而是曼哈顿距离d=∣x1−x2∣+∣y1−y2∣d=|x1-x2|+|y1-y2|d=∣x1−x2∣+∣y1−y2∣。从(1,1)(1,1)(1,1)到(n,n)(n,n)(n,n)的曼哈顿距离是2n−22n-22n−2,而题目要求2n−12n-12n−1时间内,因此,每次移动只能向右或向下,那么就是经典数字三角形。
  • 由于求最小值,需要将所有状态初始化为正无穷(这样就无法使用这些状态了),初始化状态的起点,以及状态转移越界判断。刚才那题(求最大值)就不用。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 110, INF = 1e9;int w[N][N], f[N][N];int main()
{int n;cin >> n;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )cin >> w[i][j];for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ ){if (i == 1 && j == 1) f[i][j] = w[i][j];        // 初始化起点else{f[i][j] = INF;      // 初始化if (i > 1) f[i][j] = min(f[i][j], f[i - 1][j] + w[i][j]);       // 不是第一行才能从上边走来if (j > 1) f[i][j] = min(f[i][j], f[i][j - 1] + w[i][j]);       // 不是第一列才能从左边走来}}cout << f[n][n] << endl;return 0;
}
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 110;int w[N][N], f[N][N];int main()
{int n;cin >> n;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ )cin >> w[i][j];memset(f, 0x3f, sizeof f);f[1][1] = w[1][1];for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ ){f[i][j] = min(f[i][j], f[i - 1][j] + w[i][j]);f[i][j] = min(f[i][j], f[i][j - 1] + w[i][j]);}cout << f[n][n] << endl;return 0;
}

AcWing 1027. 方格取数

  • 只走一次时(摘花生):f[i][j]f[i][j]f[i][j]表示所有从(1,1)(1,1)(1,1)走到(i,j)(i,j)(i,j)的路径的最大值,f[i][j]=max(f[i−1][j]+w[i][j],f[i][j−1]+w[i][j])f[i][j]=max(f[i-1][j]+w[i][j],f[i][j-1]+w[i][j])f[i][j]=max(f[i−1][j]+w[i][j],f[i][j−1]+w[i][j])
  • 走两次时 :让两人同时走,题目条件转化为两条路径重合部分的值只能取一次。f[i1,j1,i2,j2]f[i1,j1,i2,j2]f[i1,j1,i2,j2]表示所有从(1,1),(1,1)(1,1),(1,1)(1,1),(1,1)分别走到(i1,j1),(i2,j2)(i1,j1),(i2,j2)(i1,j1),(i2,j2)的所有路径的最大值,那么只有在i1+j1==i2+j2i1+j1 == i2+j2i1+j1==i2+j2时,两条路径的格子才可能重合。(其实就是同时走,所以步数是一样的,那么就可以从四维优化成三维了)
  • kkk表示两条路线当前走到的格子的横纵坐标之和,f[k,i1,i2]f[k,i_1,i_2]f[k,i1​,i2​]表示所有从(1,1),(1,1)(1,1),(1,1)(1,1),(1,1)分别走到(i1,k−i1),(i2,k−i2)(i_1,k-i_1),(i_2,k-i_2)(i1​,k−i1​),(i2​,k−i2​)的路径的最大值。kkk相当于就是阶段。
  • 将f[k,i1,i2]f[k,i_1,i_2]f[k,i1​,i2​]按照最后一步时两条路线分别怎么走划分成四类
  • “第一条下,第二条下” :两条路线都分别两部来求。第一条路线中从(1,1)(1,1)(1,1)走到(i1−1,k−i1)(i_1-1,k-i_1)(i1​−1,k−i1​)有多条路径,而最后一步从(i1−1.k−i1)(i_1-1.k-i_1)(i1​−1.k−i1​)走到(i1,k−i1)(i_1,k-i_1)(i1​,k−i1​)只有一条路径,要求最大值的话,先求前面的最大值,再加上最后一步的值,前面这个最大值恰好就是状态f(k−1,i1−1,i2−1)f(k-1,i_1-1,i_2-1)f(k−1,i1​−1,i2​−1),后面一步要判断一下(i1−1,k−i1),(i2−1,k−i2)(i_1-1,k-i_1),(i_2-1,k-i_2)(i1​−1,k−i1​),(i2​−1,k−i2​)是不是同一个格子,如果是同一格子…
  • 同理,后三类也会有个最大值,最后总的最大值是这四个取个max
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 15;int w[N][N];
int f[N * 2][N][N];int main()
{int n;cin >> n;int a, b, c;while (cin >> a >> b >> c, a || b || c) w[a][b] = c;for (int k = 2; k <= n + n; k ++ )for (int i1 = 1; i1 <= n; i1 ++ )for (int i2 = 1; i2 <= n; i2 ++ ){int j1 = k - i1, j2 = k - i2;if (j1 >= 1 && j1 <= n && j2 >= 1 && j2 <= n){int t = w[i1][j1];if (i1 != i2) t += w[i2][j2];int &x = f[k][i1][i2];x = max(x, f[k - 1][i1 - 1][i2 - 1] + t);x = max(x, f[k - 1][i1 - 1][i2] + t);x = max(x, f[k - 1][i1][i2] + t);x = max(x, f[k - 1][i1][i2 - 1] + t);}}cout << f[2 * n][n][n] << endl;return 0;
}

AcWing 275. 传纸条

  • 从右下角走到左上角就等价于从左上角走到右下角。那么同上题,仅有细节改动(这里两个人不能走相同格子,注意除了起点和终点)。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 55;int w[N][N];
int f[N * 2][N][N];int main()
{int n, m;cin >> n >> m;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= m; j ++ )cin >> w[i][j];for (int k = 2; k <= n + m; k ++ )for (int i = max(1, k - m); i <= n && i < k; i ++ )for (int j = max(1, k - m); j <= n && j < k; j ++ ){int t = w[i][k - i];if (i != j || k == 2 || k == n + m){t += w[j][k - j];for (int a = -1; a <= 0; a ++ )for (int b = -1; b <= 0; b ++ ){f[k][i][j] = max(f[k][i][j], f[k - 1][i + a][j + b] + t);}}}cout << f[n + m][n][n] << endl;return 0;
}

最长上升子序列模型

AcWing 1017. 怪盗基德的滑翔翼

#include <cstring>
#include <iostream>
#include <algorithm>using namespace std;const int N = 110;int n;
int h[N];
int f[N];int main()
{int T;scanf("%d", &T);while (T -- ){scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d", &h[i]);int res = 0;for (int i = 0; i < n; i ++ ){f[i] = 1;for (int j = 0; j < i; j ++ )if (h[i] < h[j])f[i] = max(f[i], f[j] + 1);res = max(res, f[i]);}memset(f, 0, sizeof f);for (int i = n - 1; i >= 0; i -- ){f[i] = 1;for (int j = n - 1; j > i; j -- )if (h[i] < h[j])f[i] = max(f[i], f[j] + 1);res = max(res, f[i]);}printf("%d\n", res);}return 0;
}

AcWing 1014. 登山

#include <iostream>
#include <algorithm>using namespace std;const int N = 1010;int n;
int h[N];
int f[N], g[N];int main()
{scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d", &h[i]);for (int i = 0; i < n; i ++ ){f[i] = 1;for (int j = 0; j < i; j ++ )if (h[i] > h[j])f[i] = max(f[i], f[j] + 1);}for (int i = n - 1; i >= 0; i -- ){g[i] = 1;for (int j = n - 1; j > i; j -- )if (h[i] > h[j])g[i] = max(g[i], g[j] + 1);}int res = 0;for (int i = 0; i < n; i ++ ) res = max(res, f[i] + g[i] - 1);printf("%d\n", res);return 0;
}

AcWing 482. 合唱队形

#include <iostream>
#include <algorithm>using namespace std;const int N = 1010;int n;
int h[N];
int f[N], g[N];int main()
{scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d", &h[i]);for (int i = 0; i < n; i ++ ){f[i] = 1;for (int j = 0; j < i; j ++ )if (h[i] > h[j])f[i] = max(f[i], f[j] + 1);}for (int i = n - 1; i >= 0; i -- ){g[i] = 1;for (int j = n - 1; j > i; j -- )if (h[i] > h[j])g[i] = max(g[i], g[j] + 1);}int res = 0;for (int i = 0; i < n; i ++ ) res = max(res, f[i] + g[i] - 1);printf("%d\n", n - res);return 0;
}

AcWing 1012. 友好城市

#include <iostream>
#include <algorithm>using namespace std;typedef pair<int, int> PII;const int N = 5010;int n;
PII city[N];
int f[N];int main()
{scanf("%d", &n);for (int i = 0; i < n; i ++ ) scanf("%d%d", &city[i].first, &city[i].second);sort(city, city + n);int res = 0;for (int i = 0; i < n; i ++ ){f[i] = 1;for (int j = 0; j < i; j ++ )if (city[i].second > city[j].second)f[i] = max(f[i], f[j] + 1);res = max(res, f[i]);}printf("%d\n", res);return 0;
}

AcWing 1016. 最大上升子序列和

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1010;int w[N], f[N];int main()
{int n;cin >> n;for (int i = 1; i <= n; i ++ ) cin >> w[i];int res = 0;for (int i = 1; i <= n; i ++ ){f[i] = w[i];for (int j = 1; j < i; j ++ )if (w[i] > w[j])f[i] = max(f[i], f[j] + w[i]);res = max(res, f[i]);}cout << res << endl;return 0;
}

AcWing 1010. 拦截导弹(贪心+stringstream语法)


  • q数组存每个子序列结尾的数。每次放进一个数都去找结尾大于等于它的最小的数,会发现,这样的话,q数组是单调递增的
  • 且发现与前面最长上升子序列问题的贪心解法一致,因此最长上升子序列的方案数等于用最少非上升子序列覆盖整个序列的方案数。
  • 不过这道题的时间复杂度卡在LIS(O(n2)O(n^2)O(n2)),因此用了二分复杂度还是这样高,没有实际意义,就不写二分了。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#include <sstream>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1010;int n;
int w[N], f[N], q[N];       // q数组记录每个子序列末尾的值int main()
{string line;getline(cin, line);stringstream sin(line);        // #include <sstream>!!while (sin >> w[n]) n ++ ;// while (cin >> w[n]) n ++ ;int res = 0, cnt = 0;for (int i = 0; i < n; i ++ ){f[i] = 1;for (int j = 0; j < i; j ++ )if (w[i] <= w[j])f[i] = max(f[i], f[j] + 1);res = max(res, f[i]);// 在单调递增的序列中找大于等于w[i]的最小的数int k = 0;while (k < cnt && q[k] < w[i]) k ++ ;       // 下标合法 && 找大于等于w[i]的数 if (k == cnt) q[cnt ++ ] = w[i];        // 下标不合法else q[k] = w[i];}cout << res << endl << cnt << endl;return 0;
}

AcWing 187. 导弹防御系统(dfs求最小步数)


  • 这题相对上题有两种选择了,就是在上一题框架之外套一层爆搜,那么爆搜需要的空间大约是2n2^n2n
  • dfs求最小步数有两种方法 :1.记一个全局最小值。2.迭代加深。这题两种都可以。此处用第一种。
  • 为什么很多题不用bfs来求解呢 ?因为bfs需要的空间太大,会把每一层都存下来,每一层有指数级别空间,而dfs只存一个路径,是线性路径。且bfs不太好剪枝,dfs是搜索树,搜的时候如果发现它的分支不太好就直接叉掉了一整棵树。这道题状态也不好用bfs。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#include <sstream>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 55;int n;
int q[N];
int up[N], down[N];
int ans;void dfs(int u, int su, int sd)
{if (su + sd >= ans) return ;if (u == n){ans = su + sd;return ;}// 情况1:将当前数放入上升子序列int k = 0;while (k < su && up[k] >= q[u]) k ++ ;int t = up[k];up[k] = q[u];if (k >= su) dfs(u + 1, su + 1, sd);else dfs(u + 1, su, sd);up[k] = t;      // 回溯// 情况2:将当前数放入下降子序列k = 0;while (k < sd && down[k] <= q[u]) k ++ ;t = down[k];down[k] = q[u];if (k >= sd) dfs(u + 1, su, sd + 1);else dfs(u + 1, su, sd);down[k] = t;
}int main()
{while (cin >> n, n){for (int i = 0; i < n; i ++ ) cin >> q[i];ans = n;        // 注意初始化!!dfs(0, 0, 0);cout << ans << endl;}
}

AcWing 272. 最长公共上升子序列


  • f[i,j]f[i,j]f[i,j]表示所有在A[1,i],B[1,j]A[1,i],B[1,j]A[1,i],B[1,j]中都出现过,且以B[j]B[j]B[j]结尾的所有公共上升子序列的集合,属性是maxmaxmax
  • 按照A[i]A[i]A[i]是否包含在公共子序列中分为两个集合,“不包含”的集合显然为f[i−1,j]f[i-1,j]f[i−1,j](所有在A[i−1],B[j]A[i-1],B[j]A[i−1],B[j]中出现,且以B[j]B[j]B[j]结尾的所有…),“包含”则分为这个公共子序列中倒数第二个是什么,分成若干类 :第一类:不存在倒数第二个数,即公共上升子序列长度是1;第二类 :倒数第二个数是B[1]B[1]B[1];第三类 :倒数第二个数是B[2]B[2]B[2];…;倒数第二个数是B[j−1]B[j-1]B[j−1]。即一共j种可能,分为j个子集,要想求右边这个的最大值就是求这j个子集的maxmaxmax
  • 但这样的朴素做法是O(N3)O(N^3)O(N3),无法通过。dp的优化需要根据代码等价变形,因此我们先写出朴素写法。
// TLE
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#include <sstream>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 3e3 + 10;int a[N], b[N];
int f[N][N];int main()
{int n;cin >> n;for (int i = 1; i <= n; i ++ ) cin >> a[i];for (int i = 1; i <= n; i ++ ) cin >> b[i];for (int i = 1; i <= n; i ++ )for (int j = 1; j <= n; j ++ ){f[i][j] = f[i - 1][j];if (a[i] == b[j]){int maxv = 1;for (int k = 1; k < j; k ++ )if (b[k] < b[j])maxv = max(maxv, f[i - 1][k] + 1);f[i][j] = max(f[i][j], maxv);}}int res = 0;for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);cout << res << endl;return 0;
}

  • 优化 :b[j] == a[i],因此转化为a[i],这个循环就是求在b[1]…b[j-1]中所有小于a[i]的元素中,它所对应的f[i-1,k]的最大值再加1。这样的话,在求b[j+1]时会再把前面这个循环循环一遍,重新看一遍对应的f的最大值
  • 因此我们用maxv直接存前缀中打对勾的所对应的最大值即可,在求b[j+1]时就不需要重新枚举了,直接判断b[j+1]即可
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#include <sstream>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 3e3 + 10;int a[N], b[N];
int f[N][N];int main()
{int n;cin >> n;for (int i = 1; i <= n; i ++ ) cin >> a[i];for (int i = 1; i <= n; i ++ ) cin >> b[i];for (int i = 1; i <= n; i ++ ){int maxv = 1;for (int j = 1; j <= n; j ++ ){f[i][j] = f[i - 1][j];if (a[i] == b[j]) f[i][j] = max(f[i][j], maxv);if (b[j] < a[i]) maxv = max(maxv, f[i - 1][j] + 1);       // 只有在b[j]<a[i]的情况下才会被打对勾,才可能用对应的f更新maxv}}int res = 0;for (int i = 1; i <= n; i ++ ) res = max(res, f[n][i]);cout << res << endl;return 0;
}

背包模型

背包问题初始化总结


总的来说就是 :求方案数,f[0]=1f[0]=1f[0]=1;求最大/最小值 :f[0]=0f[0]=0f[0]=0

一、01背包

AcWing 423. 采药


板子

#include <bits/stdc++.h>
using namespace std;const int N = 1010;int f[N];int main()
{int n, m;cin >> m >> n;for (int i = 0; i < n; i ++ ){int v, w;cin >> v >> w;for (int j = m; j >= v; j -- )f[j] = max(f[j], f[j - v] + w);}cout << f[m] << endl;return 0;
}

AcWing 1024. 装箱问题


价值和体积是同一个变量。注意题目所求为剩余。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 2e4 + 10;int f[N];int main()
{int n, m;cin >> m >> n;for (int i = 0; i < n; i ++ ){int v;cin >> v;for (int j = m; j >= v; j -- )f[j] = max(f[j], f[j - v] + v);}cout << m - f[m] << endl;return 0;
}

AcWing 1022. 宠物小精灵之收服(二维体积)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1010;int f[N][N];int main()
{int V1, V2, n;cin >> V1 >> V2 >> n;for (int i = 0; i < n; i ++ ){int v1, v2;cin >> v1 >> v2;for (int j = V1; j >= v1; j -- )for (int k = V2 - 1; k >= v2; k -- )f[j][k] = max(f[j][k], f[j - v1][k - v2] + 1);}cout << f[V1][V2 - 1] << " ";for (int i = 0; i < V2; i ++ )if (f[V1][V2 - 1] == f[V1][i]){cout << V2 - i << endl;break;}return 0;
}

AcWing 278. 数字组合(体积恰好,求总方案数)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1e4 + 10;int f[N];int main()
{int n, m;cin >> n >> m;f[0] = 1;for (int i = 0; i < n; i ++ ){int v;cin >> v;for (int j = m; j >= v; j -- )f[j] += f[j - v];}cout << f[m] << endl;return 0;
}

AcWing 8. 二维费用的背包问题(二维体积)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 110;int f[N][N];int main()
{int n, V1, V2;cin >> n >> V1 >> V2;for (int i = 0; i < n; i ++ ){int v1, v2, w;cin >> v1 >> v2 >> w;for (int j = V1; j >= v1; j -- )for (int k = V2; k >= v2; k -- )f[j][k] = max(f[j][k], f[j - v1][k - v2] + w);}cout << f[V1][V2] << endl;return 0;
}

AcWing 1020. 潜水员(二维体积,体积至少,最小价值)

注意状态转移时体积为负数也是合法的。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 85;int f[N][N];int main()
{int V1, V2, n;cin >> V1 >> V2 >> n;memset(f, 0x3f, sizeof f);f[0][0] = 0;for (int i = 0; i < n; i ++ ){int v1, v2, w;cin >> v1 >> v2 >> w;for (int j = V1; j >= 0; j -- )for (int k = V2; k >= 0; k -- )f[j][k] = min(f[j][k], f[max(0, j - v1)][max(0, k - v2)] + w);}cout << f[V1][V2] << endl;
}

AcWing 426. 开心的金明

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 3e4 + 10;int f[N];int main()
{int n, m;cin >> m >> n;for (int i = 0; i < n; i ++ ){int v, p;cin >> v >> p;p *= v;for (int j = m; j >= v; j -- )f[j] = max(f[j], f[j - v] + p);}cout << f[m] << endl;return 0;
}

AcWing 11. 背包问题求方案数(求最优选法的方案数)

  • g[i][j]g[i][j]g[i][j]表示f[i][j]f[i][j]f[i][j]取最大值的方案数
  • 由于在讨论f[i][j]f[i][j]f[i][j]的maxmaxmax时会将这个集合划分成两半,即不选iii更新为f[i−1][j]f[i-1][j]f[i−1][j],选iii更新为f[i−1][j−v[i]]+w[i]f[i-1][j-v[i]]+w[i]f[i−1][j−v[i]]+w[i]
  • 如果不选iii更大,g[i][j]g[i][j]g[i][j]更新为g[i−1][j]g[i-1][j]g[i−1][j],选iii更大则更新为g[i−1][j−v[i]]g[i-1][j-v[i]]g[i−1][j−v[i]],如果相等则更新为g[i−1][j]+g[i−1][j−v[i]]g[i-1][j]+g[i-1][j-v[i]]g[i−1][j]+g[i−1][j−v[i]]
  • g[i][j]g[i][j]g[i][j]的优化 :这里第iii层也只和第i−1i-1i−1层有关系,且j也只和更小的j有关系,所以g也可以优化成一维,所以这道题可以用一维写。
  • 注意这里f[i][j]f[i][j]f[i][j]需要存储为“体积恰好为j“而非至多是j,否则涉及容斥定理。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
const double pi = acos(-1);
typedef long long ll;const int N = 1e3 + 10, mod = 1e9 + 7;int f[N], g[N];int main()
{memset(f, -0x3f, sizeof f);f[0] = 0;g[0] = 1;int n, m;scanf("%d%d", &n, &m);for (int i = 1; i <= n; i ++ ){int v, w;scanf("%d%d", &v, &w);for (int j = m; j >= v; j -- ){// 两个if而不是else ifint cnt = 0;int maxv = max(f[j], f[j - v] + w);if (f[j] == maxv) cnt += g[j];if (f[j - v] + w == maxv) cnt += g[j - v];g[j] = cnt % mod;f[j] = maxv;}}int res = 0, cnt = 0;// 题目所求为“体积最多为”,这里状态表示的是“体积恰好为”,所以价值最大的并不一定是体积最大的for (int i = 1; i <= m; i ++ ) res = max(res, f[i]);for (int i = 1; i <= m; i ++ )if (f[i] == res)cnt = (cnt + g[i]) % mod;printf("%d\n", cnt);return 0;
}

AcWing 12. 背包问题求具体方案(打印方案)

  • 由于求字典序最小 :能选第一个物品就必须选第一个,能选第二个就必须选第二个…即前面的物品能选则选,所有在更新时左右两个集合都可以选时,优先选择右边f[i−1][j−v[i]]+w[i]f[i-1][j-v[i]]+w[i]f[i−1][j−v[i]]+w[i]的集合;如果右边可以选左边不可,必然选右边;如果左边可以右边不可以,就不能取第iii个物品。
  • dp时需要从后往前推,那么在求方案时就可以从前往后了,通过判断f[i][j]f[i][j]f[i][j]的值等于左边还是右边来判断第iii个物品又没有选择。
  • 求方案时就不能压缩空间了,由于不压缩空间,体积从小到大循环和从大到小循环都一样。
  • 由于从后往前推,f[i][j]f[i][j]f[i][j]是从i+1i+1i+1更新的。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1010;int f[N][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 = n; i; 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]);}int j = m;for (int i = 1; i <= n; i ++ )if (j >= v[i] && f[i][j] == f[i + 1][j - v[i]] + w[i]){cout << i << " ";j -= v[i];}return 0;
}

AcWing 734. 能量石 (贪心)

  • 考虑任意两个(是从这个大的集合里任选的)相邻的能量石iii和i+1i + 1i+1,假设先吃iii再吃i+1i + 1i+1,且假定吃的时候两块能量石能量都大于0(其实一定满足,因为它在那个大的集合内,且那个大的集合不吃能量为0的),总共能获得的能量是Ei+Ej−si∗li+1E_i + E_j - s_i * l_{i+1}Ei​+Ej​−si​∗li+1​,反之就是Ei+Ej−si+1∗liE_i + E_j - s_{i+1}*l_iEi​+Ej​−si+1​∗li​。因此,只要有si∗ll+1<si+1∗lis_i*l_{l+1} < s_{i+1}*l_isi​∗ll+1​<si+1​∗li​,就一定有先吃i再吃i+1更好,这个整理一下就是sili<si+1li\frac{s_i}{l_i}<\frac{s_{i+1}}{l_i}li​si​​<li​si+1​​,因此将所有能量石按这个从小到大排序,一定是最优的。因此可以证明最优方案一定是在小圈(从从小到大排好序中选)里的,所以只要找小圈里的最优方案即可。
  • f[i][j]f[i][j]f[i][j]表示只从前i块能量石中选,且总体积“恰好”是j的方案,属性是maxmaxmax。
  • 转移方程f[j]=max(f[j],f[j−s]+e−(j−s)∗l)f[j]=max(f[j],f[j-s]+e-(j-s)*l)f[j]=max(f[j],f[j−s]+e−(j−s)∗l)
  • m是所有能量石时间(体积)之和。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1e4 + 10;     // N * Sint f[N];struct Stone
{int s, e, l;bool operator< (const Stone &W) const{return s * W.l < W.s * l;}
}stone[N];int main()
{int _; cin >> _;for (int C = 1; C <= _; C ++ ){int n;cin >> n;int m = 0;for (int i = 0; i < n; i ++ ){cin >> stone[i].s >> stone[i].e >> stone[i].l;m += stone[i].s;}sort(stone, stone + n);memset(f, -0x3f, sizeof f);f[0] = 0;for (int i = 0; i < n; i ++ ){int s = stone[i].s, e = stone[i].e, l = stone[i].l;for (int j = m; j >= s; j -- )f[j] = max(f[j], f[j - s] + e - (j - s) * l);}int res = 0;for (int i = 0; i <= m; i ++ ) res = max(res, f[i]);cout << "Case #" << C << ": " << res << endl;}
}

二、完全背包

AcWing 1023. 买书(体积恰好,求总方案数)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1010;int f[N];
int v[] = {10, 20, 50, 100};int main()
{int m;cin >> m;f[0] = 1;for (int i = 0; i < 4; i ++ )for (int j = v[i]; j <= m; j ++ )f[j] += f[j - v[i]];cout << f[m] << endl;return 0;
}

AcWing 1021. 货币系统(体积恰好,求总方案数)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 3010;ll f[N];int main()
{int n, m;cin >> n >> m;f[0] = 1;for (int i = 0; i < n; i ++ ){int v;cin >> v;for (int j = v; j <= m; j ++ )f[j] += f[j - v];}cout << f[m] << endl;return 0;
}

AcWing 532. 货币系统(体积恰好,求总方案数)

  • 发现有三个性质 :1.a1a_1a1​, … , ana_nan​一定都能被表示出来。2.在最优解中,bibibi一定是从aaa中选的。3.b1b1b1 , … , bmb_mbm​一定不能被其他bib_ibi​表示出来。
  • 因此,从小到大排序,判断aia_iai​能否被若干个a1a_1a1​,…,ai+1a_{i + 1}ai+1​表示,如果能则说明aia_iai​是多余的,一定不选,否则一定选。
  • 问题转化为能否用无穷个体积为a1a_1a1​, … ai−1a_{i-1}ai−1​的物品恰好装满容积为aia_iai​的背包,转化为完全背包问题判断方案数是否为0。

// 这是一道线性代数问题
// 求解一个向量组的秩(最大无关向量组的向量个数)
// 但代码写起来就是一个模拟筛的过程
// 从小到大,首先查看当前数是否已经被筛掉
// 1)如果没有就将它加入到最大无关向量组中,并把它以及它和此前的硬币的线性组合都筛掉
// 2)如果有就跳过
// 即,在完全背包求方案数的过程中,统计那些初始没有方案数的物品#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 110, M = 25010;int a[N], f[M];int main()
{int _; cin >> _;while (_ -- ){int n;cin >> n;for (int i = 0; i < n; i ++ ) cin >> a[i];memset(f, 0, sizeof f);f[0] = 1;sort(a, a + n);//我们只需统计所有物品的体积是否能被其他的线性表出//因此背包的体积只需设置为最大的物品体积即可//res用来记录最大无关向量组的个数int m = a[n - 1];int res = 0;for (int i = 0; i < n; i ++ ){//如果当前物品体积被之前的物品组合线性筛掉了,则它是无效的if (f[a[i]]) continue;//如果没有被筛掉,则把它加入最大无关向量组res ++ ;//筛掉当前最大无关向量组能线性表示的体积for (int j = a[i]; j <= m; j ++ )f[j] += f[j - a[i]];}cout << res << endl;}return 0;
}

三、多重背包

AcWing 6. 多重背包问题 III


当求j−vj - vj−v时其实求的是前面sss个长度的窗口中的最大值,“前面sss个的最大值“,也就是滑动窗口求极值,再转化为用单调队列求解

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 2e4 + 10;int f[N], g[N], q[N];int main()
{int n, m;cin >> n >> m;for (int i = 0; i < n; i ++ ){int v, w, s;cin >> v >> w >> s;memcpy(g, f, sizeof f);for (int j = 0; j < v; j ++ ){int hh = 0, tt = -1;for (int k = j; k <= m; k += v){if (hh <= tt && k - q[hh] > s * v) hh ++ ;if (hh <= tt) f[k] = max(f[k], g[q[hh]] + (k - q[hh]) / v * w);while (hh <= tt && g[q[tt]] - (q[tt] - j) / v * w <= g[k] - (k - j) /v * w) tt -- ;q[ ++ tt] = k;}}}cout << f[m] << endl;
}

AcWing 1019. 庆功会


3e7居然过了。

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 6010;int f[N];int main()
{int n, m;cin >> n >> m;for (int i = 0; i < n; i ++ ){int v, w, s;cin >> v >> w >> s;for (int j = m; j >= 0; j -- )for (int k = 0; k <= s && k * v <= j; k ++ )f[j] = max(f[j], f[j - k * v] + k * w);}cout << f[m] << endl;return 0;
}

四、分组背包

AcWing 1013. 机器分配(打印路径)

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 20;int f[N][N];
int w[N][N];
int way[N];int main()
{int n, m;cin >> n >> m;for (int i = 1; i <= n; i ++ )for (int j = 1; j <= m; j ++ )cin >> w[i][j];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 <= m; k ++ )if (j >= k)f[i][j] = max(f[i][j], f[i - 1][j - k] + w[i][k]);}cout << f[n][m] << endl;int j = m;for (int i = n; i; i -- )for (int k = 0; k <= j; k ++ )if (f[i][j] == f[i - 1][j - k] + w[i][k]){way[i] = k;j -= k;break;}for (int i = 1; i <= n; i ++ ) cout << i << " " << way[i] << endl;return 0;
}

五、混合背包

AcWing 7. 混合背包问题

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <string>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#include <stack>
#include <queue>
#include <deque>
#include <ctime>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
#define lowbit(x) (x&-x)
using namespace std;
const double pi = acos(-1);
typedef long long ll;
typedef pair<int, int> PII;
typedef pair<long, long> PLL;const int N = 1e3 + 10;int f[N];int main()
{int n, m;cin >> n >> m;for (int i = 0; i < n; i ++ ){int v, w, s;cin >> v >> w >> s;if (!s){for (int j = m; j >= v; j -- )f[j] = max(f[j], f[j - v] + w);}else{if (s == -1) s = 1;for (int k = 1; k <= s; k *= 2){for (int j = m; j >= k * v; j -- )f[j] = max(f[j], f[j - k * v] + k * w);s -= k;}if (s > 0)for (int j = m; j >= s * v; j -- )f[j] = max(f[j], f[j - s * v] + s * w);}}cout << f[m] << endl;return 0;
}

六、有依赖的背包问题

AcWing 10. 有依赖的背包问题

  • f[u][j]f[u] [j]f[u][j]表示所有从以uuu为根的子树中选,且总体积不超过jjj的方案
  • 每棵子树内部以所选体积来划分,也就是说每棵子树内部体积有m+1m+1m+1种选法,摆脱了2k2^k2k级别,每一类中取最大即可
  • 在递归考虑每一个节点内部的时候,就转化成了分组背包问题
  • 如何存树 :数组模拟邻接表,且使用单链表;
  • 注意这里根节点不一定是1号点。
#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
const double pi = acos(-1);
typedef long long ll;const int N = 110;int e[N], ne[N], h[N], idx;int f[N][N];
int v[N], w[N];
int n, m;void add(int a, int b)
{e[idx] = b, ne[idx] = h[a], h[a] = idx ++ ;
}void dfs(int u)
{for (int i = h[u]; ~i; i = ne[i])       // 循环物品组{int son = e[i];dfs(son);// 分组背包for (int j = m - v[u]; j >= 0; j -- )       // 循环体积for (int k = 0; k <= j; k ++ )      // 循环决策f[u][j] = max(f[u][j], f[u][j - k] + f[son][k]);}// 将物品u加进去
//    for (int i = v[u]; i <= m; i ++ ) f[u][i] = f[u][i - v[u]] + w[u];for (int i = m; i >= v[u]; i -- ) f[u][i] = f[u][i - v[u]] + w[u];for (int i = 0; i < v[u]; i ++ ) f[u][i] = 0;
}int main()
{scanf("%d%d", &n, &m);// 初始化图memset(h, -1, sizeof h);// 找根int root;for (int i = 1; i <= n; i ++ ){int p;scanf("%d%d%d", &v[i], &w[i], &p);if (p == -1) root = i;else add(p, i);}// 从根开始dfs,而非从1节点开始dfs(root);printf("%d\n", f[root][m]);return 0;
}

AcWing 487. 金明的预算方案

#include <iostream>
#include <algorithm>
#include <cmath>
#include <cstring>
#include <vector>
#include <unordered_map>
#include <unordered_set>
#include <set>
#include <map>
#define endl '\n'
#define IOS ios::sync_with_stdio(false); cin.tie(0); cout.tie(0)
using namespace std;
const double pi = acos(-1);
typedef long long ll;typedef pair<int, int> PII;const int N = 65, M = 32010;int n, m;
int f[M];
PII master[N];
vector<PII> servant[N];int main()
{IOS;cin >> m >> n;for (int i = 1; i <= n; i ++ ){int v, p, q;cin >> v >> p >> q;p *= v;if (!q) master[i] = {v, p};else servant[q].push_back({v, p});        // servant[q]而非i}for (int i = 1; i <= n; i ++ )for (int u = m; u >= 0; u -- ){for (int j = 0; j < 1 << servant[i].size(); j ++ ){int v = master[i].first, w = master[i].second;       // 注意定义的位置不在i层for (int k = 0; k < servant[i].size(); k ++ )if (j >> k & 1){v += servant[i][k].first;w += servant[i][k].second;}if (u >= v) f[u] = max(f[u], f[u - v] + w);}}cout << f[m] << endl;return 0;
}

数字三角形,最长上升子序列,背包模型 AcWing算法提高课 (详解)相关推荐

  1. DP 状态机模型 AcWing算法提高课 详解

    状态机模型 AcWing 1049. 大盗阿福 #include <iostream> #include <algorithm> #include <cmath> ...

  2. OSI 七层模型和TCP/IP模型及对应协议(详解)

    OSI 七层模型和TCP/IP模型及对应协议(详解) 查看全文 http://www.taodudu.cc/news/show-6185847.html 相关文章: OSI7层网络模型协议精析 OSI ...

  3. Meta最新模型LLaMA细节与代码详解

    Meta最新模型LLaMA细节与代码详解 0. 简介 1. 项目环境依赖 2. 模型细节 2.1 RMS Pre-Norm 2.2 SwiGLU激活函数 2.3 RoPE旋转位置编码 3. 代码解读 ...

  4. php sprintf 后面补0,PHP数字前补0的自带函数sprintf 和number_format的用法(详解)

    下面小编就为大家带来一篇PHP数字前补0的自带函数sprintf 和number_format的用法(详解).小编觉得挺不错的,现在就分享给大家,也给大家做个参考.一起跟随小编过来看看吧 很多时候我们 ...

  5. 【深度学习】扩散模型(Diffusion Model)详解

    [深度学习]扩散模型(Diffusion Model)详解 文章目录 [深度学习]扩散模型(Diffusion Model)详解 1. 介绍 2. 具体方法 2.1 扩散过程 2.2 逆扩散过程 2. ...

  6. Tensorflow 2.x(keras)源码详解之第十章:keras中的模型保存与加载(详解Checkpointmd5模型序列化)

      大家好,我是爱编程的喵喵.双985硕士毕业,现担任全栈工程师一职,热衷于将数据思维应用到工作与生活中.从事机器学习以及相关的前后端开发工作.曾在阿里云.科大讯飞.CCF等比赛获得多次Top名次.现 ...

  7. python【数据结构与算法】动态规划详解从背包到最长公共子序列(看不懂你来打我)

    文章目录 1 引入 2 01背包 3 完全背包问题 4 多重背包问题 5 最长公共子序列 1 引入 0-1背包问题是最广为人知的动态规划问题之一,拥有很多变形.尽管在理解之后并不难写出程序,但初学者往 ...

  8. 最长上升子序列(LIS)算法

    LIS定义 LIS(Longest Increasing Subsequence)最长上升子序列  一个数的序列bi,当b1 < b2 < - < bS的时候,我们称这个序列是上升的 ...

  9. c语言最长递增子序列nlogn,十月常见算法考题、最长递增子序列,Leetcode第300题最长上升子...

    十月常见算法考题.最长递增子序列,Leetcode第300题最长上升子 十月常见算法考题.最长递增子序列,Leetcode第300题最长上升子序列的变种,我没见过乔丹,今天詹姆斯就是我的神! @Aut ...

最新文章

  1. 研究:多感官教学增强记忆 学习效率事半功倍
  2. 刚安装完的ubuntu安装谷歌浏览器
  3. fedro1 16 64位安装oracle 11.2.0.1遇到的问题
  4. x265中checkMerge2Nx2N_rd0_4()分析(版本2.8)
  5. 安防系统管理服务器,安防弱电系统设计常用十个行业方案(含拓扑图)
  6. Angular4_安全导航操作符 ( ?. ) 和空属性路径
  7. w ndows10家庭版和企业版谁好用,Windows10系统哪个版本好?Win10家庭版和专业版的区别介绍...
  8. wireshark 过滤omci包_中兴OLT、ONU常见故障问题处理
  9. 艾司博讯:拼多多推广投放时间设置步骤
  10. 用狼的处世哲学做SOHO 一
  11. 开发一个Android志愿填报系统(后台管理+前台app)毕业设计
  12. 26个音序的正确写法和占格_26个音序表怎么读(拼音音序表的正确写法)
  13. es报Unexpected character (‘ï‘ (code 239)): was expecting comma to separate Object entries解决方法
  14. 分布式项目-谷粒商城。
  15. 【Python】max()中key的使用
  16. 这么多的内置函数能记住吗?对python的68个内置函数分类总结!
  17. 2013应届毕业生各大IT公司待遇整理汇总篇(转)
  18. 最好用的文字锁屏APP的使用教程
  19. AES加密算法及演示程序(GO-算法核心实现+Python-前端演示系统)
  20. python 分解变量

热门文章

  1. SE43自定义sap菜单
  2. SAP 730模糊查询时不可以输入连续的汉字问题解决方案
  3. SAP Batch表MCH1和MCHA的差别?
  4. Web Dynpro公开课学习
  5. 2015年中国钢铁企业排名50强名单
  6. SM35/BDC Record / Log 导出
  7. 判断程序是否通过RFC运行
  8. 上市公司总市值TOP10出炉,你所在县区看的到未来吗?
  9. “冷潮”之后,P2P或更加适合投资
  10. ecshop清除mysql缓存_禁用ecshop缓存,关闭ecshop缓存功能