目录

  • 0x52. 动态规划 - 背包
    • 0x52.1 0/10/10/1 背包
      • Problem A. 数字组合
      • Problem B. 背包问题求具体方案
      • Problem C. jury Compromise(多维度 0/1 背包,输出方案)
      • Problem D. Proud Merchants(有顺序的 0/1 背包)
      • Problem E. Bag Problem(搜索剪枝求解 0/1 背包)
      • Problem F. 砝码称重
    • 0x52.2 完全背包
      • Problem A. 自然数拆分
      • Problem B. CRB and His Birthday
      • Problem C. Partial Tree(有个数限制的完全背包)
      • Problem D. 付公主的背包(生成函数求解背包计数问题)
    • 0x52.3 多重背包
      • Problem A. 硬币(贪心优化)
      • Problem B. The Fewest Coins (负权多重背包)
    • 0x52.4 分组背包
      • Problem A. I love sneakers! (分组背包,至少1个)
      • Problem B. Balance (分组背包,正好1个)
      • Problem C. AreYouBusy(混合分组背包,至少1个,至多1个,0/1背包)
      • Problem D. Permutation (置换群 ,算数基本定理 ,分组背包,至多1个)
      • Problem E. Least common multiple(算数基本定理 ,分组背包,至多1个)

本系列博客是《算法竞赛进阶指南》的学习笔记,包含书中的部分重要知识点、例题解题报告及我个人的学习心得和对该算法的补充拓展,仅用于学习交流和复习,无任何商业用途。博客中部分内容来源于书本和网络 ,由我个人整理总结。部分内容由我个人编写而成,如果想要有更好的学习体验或者希望学习到更全面的知识,请于京东搜索购买正版图书:《算法竞赛进阶指南》——作者李煜东,强烈安利,好书不火系列,谢谢配合。
%
学习笔记目录链接: 学习笔记目录链接
%
整理的算法模板合集: ACM模板
%
点我看算法全家桶系列!!!


0x52. 动态规划 - 背包

0x52.1 0/10/10/1 背包

Template

给定 NNN 个物品,其中第 iii 个物品的体积为 ViV_iVi​,价值为 WiW_iWi​,有一个容积为 MMM 的背包, 求选择一些物品放入背包,使得物品的总体积不超过 MMM 的前提下,物品的价值总和最大,即背包不一定装满。

Solution

显然是一个线性DP,我们选择已处理的物品数和当前总体积作为DP的阶段
设 f[i,j]f[i, j]f[i,j] 从前 iii 个物品中选出总体积 jjj 物品放入背包的最大价值。

f[i][j]=f[i−1][j]f[i][j] = f[i - 1][j]f[i][j]=f[i−1][j] 不选择第 iii 个物品
f[i][j]=max⁡{f[i][j−v[i]]+w[i]}f[i][j] = \max\{f[i][j - v[i]] + w[i]\}f[i][j]=max{f[i][j−v[i]]+w[i]} 选择第 iii 个物品

初始化 f[0,0]=0f[0, 0] = 0f[0,0]=0

可以写出暴力转移代码:

f[maxn][maxn];
memset(f, 0xcf, sizeof f);f[0][0] = 0;
for (int i = 1; i <= n; ++ i) {for (int j = 0; j <= m; ++ j)f[i][j] = f[i - 1][j];for (int j = v[i], j <= m; ++ j)f[i][j] = max(f[i][j], f[i - 1][j - v[i]] + w[i]);
}

由于 f[i][]f[i][]f[i][] 仅与 f[i−1][]f[i -1][]f[i−1][] 有关,显然可以使用滚动数组优化。
由于转移方程中 f[i][j]=f[i−1][j]f[i][j] = f[i - 1][j]f[i][j]=f[i−1][j] ,每次需要做一次拷贝,因此在做滚动数组的时候不需要清空。

f[2][maxn];for (int i = 1; i <= n; ++ i) {for (int j = 0; j <= m; ++ j)f[i & 1][j] = f[i - 1 & 1][j];for (int j = v[i]; j <= m; ++ j)f[i & 1][j] = max(f[i & 1][j], f[i - 1 & 1][j - v[i]] + w[i]);
}int ans = 0;
for (int j = 1; j <= m; ++ j)ans = max(ans, f[n & 1][j]);

由于滚动数组的时候每次仅需拷贝无需清空,所以我们发现可以直接去掉第一维,在枚举到第 iii 个物品的时候
f[j]f[j]f[j] 表示背包中放入总体积为 jjj 的物品的最大价值和。但是由于 0/1 背包每个物品仅能使用一次,所以我们需要
倒序枚举,防止 f[i][j]f[i][j]f[i][j] 从 f[i][j−v[i]]f[i][j - v[i]]f[i][j−v[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]);
int ans = 0;
for (int j = 1; j <= m; ++ j) ans = max(ans, f[j]);

Problem A. 数字组合

AcWing 278

给定 NNN 个正整数,从中选出若干个数,使得它们的和是 MMM ,求有多少种选择方案。

1≤N≤100,1≤M≤10001\le N \le 100, 1\le M \le 10001≤N≤100,1≤M≤1000

Solution

显然是一个 0/1 背包的模型求总方案数,我们将转移时的 max⁡\maxmax 改为求和即可。

f[i,j]f[i, j]f[i,j] 表示取前 iii 个数字,和为 jjj 的方案数。这里相当于必须装满的背包。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 1e5 + 6;
int n, m, s, t;
int a[N];
int f[N];int main()
{scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++ i)scanf("%d", &a[i]);f[0] = 1;for (int i = 1; i <= n; ++ i) for (int j = m; j >= a[i]; -- j)f[j] += f[j - a[i]];cout << f[m] << endl;return 0;
}

Problem B. 背包问题求具体方案

AcWing 12

有 NNN 件物品和一个容量是 VVV 的背包。每件物品只能使用一次。

第 iii 件物品的体积是 viv_ivi​,价值是 wiw_iwi​。

求解将哪些物品装入背包,可使这些物品的总体积不超过背包容量,且总价值最大。

输出 字典序最小的方案。这里的字典序是指:所选物品的编号所构成的序列。物品的编号范围是 1…N1…N1…N。

0<N,V≤1000,0<vi,wi≤10000<N,V≤1000,0<v_i,w_i≤10000<N,V≤1000,0<vi​,wi​≤1000
Solution

0/1 背包转移之后,倒序再遍历一遍输出方案即可。

因为要求按字典序输出,倒序循环枚举物品,正序循环输出方案即可。

Code

#include<cstdio>
#include<algorithm>
#include<iostream>
#include<cstring>using namespace std;const int N = 5007;
int n, m;
int f[N][N];
int v[N], w[N];
int main(){scanf("%d%d", &n, &m);for(int i = 1; i <= n; ++ i)scanf("%d%d", &v[i], &w[i]);for(int i = n; i >= 1; -- i){for(int j = m; j >= 0; -- 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]){printf("%d ", i);j -= v[i];}}puts("");return 0;
}

Problem C. jury Compromise(多维度 0/1 背包,输出方案)

AcWing 280

从 NNN 个人中选择 MMM 个人。第 iii个人有 ai,bia_i,b_iai​,bi​ 两种分数。
选择的 MMM 个人必须满足他们的 D=∑i=1Mai,P=∑i=1Mbi\displaystyle D=\sum_{i = 1}^M a_i,P=\sum_{i = 1}^M b_iD=i=1∑M​ai​,P=i=1∑M​bi​ ,满足 ∣D−P∣|D-P|∣D−P∣ 最小。

若选择方法不唯一,则在从中选出 D+PD+PD+P 最大的方案。
求最终的 DDD、PPP 以及选择的人的编号。

1≤N≤200,1≤M≤201\le N\le 200, 1\le M \le 201≤N≤200,1≤M≤20

Solution

显然是一个 0/10/10/1 背包模型,但是有多种维度的体积。
我们可以把 NNN 个人看做 NNN 个物品,从中选出 MMM 个人, D−PD - PD−P 最小
即有三种体积:人数,DDD,PPP
直接维护就是 F[i,j,k,l]F[i, j, k, l]F[i,j,k,l] 表示前 iii 个人中选出 jjj 个人,D=kD = kD=k, P=lP = lP=l 的状态是否可行,即 boolboolbool 数组 fff。
转移方程为:

f[i][j][k][l]=f[i−1][j][k][l]∣f[i−1][j−1][k−a[i]][l−b[i]]f[i][j][k][l] = f[i - 1][j][k][l] \mid f[i - 1][j - 1][k - a[i]][l - b[i]]f[i][j][k][l]=f[i−1][j][k][l]∣f[i−1][j−1][k−a[i]][l−b[i]]

即选或不选第 iii 个人。复杂度为 O(N×M5)O(N\times M^5)O(N×M5) ,显然会超时,考虑优化。

首先 fff 显然没必要开 iii 这一维度,我们可以滚动数组优化或者直接循环枚举 iii 即可表示前 iii 个人。然后 kkk 和 lll 所代表的 DDD,PPP,我们并不关心 DDD 和 PPP 分别是多少,我们关心最小的 ∣D−P∣|D - P|∣D−P∣ 是多少,以及此时最大的 D+PD + PD+P 是多少。

由于 D,PD,PD,P 表示的是总和,显然我们局部最优一定保证整体最优,因此我们可以令每个人的差值 ai−bia_i - b_iai​−bi​ 作为背包的体积进行枚举转移(∣D+P∣|D+P|∣D+P∣ 中绝对值在外面,所以应该先求和最后去绝对值…),由于我们希望求得的是差值为 kkk 时的最大的 D+PD + PD+P,因此我们可以令 D+PD + PD+P 作为物品的价值去取最大值。

即令 f[j,k]f[j, k]f[j,k] 表示在循环到 iii 时,前 iii 个人中选出了 jjj 个人,此时 ∣D−P∣|D-P|∣D−P∣ 为 kkk ,D+PD+PD+P 的最大值。

有转移方程:

f[j,k]=max⁡{f[j,k],f[j−1,k−(a[i]−b[i])]+a[i]+b[i]}f[j, k] = \max\{f[j, k], f[j - 1, k - (a[i] - b[i])] +a[i] +b[i]\} f[j,k]=max{f[j,k],f[j−1,k−(a[i]−b[i])]+a[i]+b[i]}
初始化 f[0,0]=0f[0, 0] = 0f[0,0]=0,其余为负无穷(因为 a[i]−b[i]a[i] - b[i]a[i]−b[i] 可以为负数)

目标:找到 F[M,k]F[M, k]F[M,k] 中最小的 ∣k∣|k|∣k∣ , ∣k∣|k|∣k∣ 相同的时候 f[M,k]f[M, k]f[M,k] 最大。

复杂度 O(N×M3)O(N\times M^3)O(N×M3)

其中在我们枚举 kkk 的时候,k∈[−400,400]k\in [-400, 400]k∈[−400,400],数组不能开负数,我们直接设置一个偏移量,整体向右平移, +400 即可。

最后记录转移路径输出方案即可,我们使用 bool 数组 choose[i][j][k] 表示选择 jjj 个人,差值为 kkk 时第 iii 个人选或不选。

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 200 + 7, maxm = 20 + 7, maxk = 20 * 20 * 2 + 7, INF = 0x3f3f3f3f;//f[j, k] 表示前 i 个人中选择 j 个人,差值为 k,D+P 的最大值
int n, m, s, t, ans, kcase;
int f[maxn][maxk];
int a[maxn], b[maxn];
int choose [maxn][maxm][maxk];void print(int i, int j, int k)
{if(j == 0) return;if(choose[i][j][k + 400]) {print(i - 1, j - 1, k - (a[i] - b[i]));printf(" %d", i);}else print(i - 1, j, k);
}int main()
{while(scanf("%d%d", &n, &m) != EOF && n + m) {for (int i = 1; i <= n; ++ i) scanf("%d%d", &b[i], &a[i]); memset(f, 0xcf, sizeof f);ans = 0;f[0][0 + 400] = 0;for (int i = 1; i <= n; ++ i) {for (int j = m; j >= 1; -- j) {for (int k = -20 * m; k <= 20 * m; ++ k) {choose[i][j][k + 400] = false;if(k - (a[i] - b[i]) < -20 * m || k - (a[i] - b[i]) > 20 * m) continue;if(f[j][k + 400] < f[j - 1][k - (a[i] - b[i]) + 400] + a[i] + b[i]) {f[j][k + 400] = f[j - 1][k - (a[i] - b[i]) + 400] + a[i] + b[i];choose[i][j][k + 400] = true;} }}}int delta = INF;int raw_delta, sum = 0, ansk = -1;for (int k = -20 * m; k <= 20 * m; ++ k) {if(f[m][k + 400] >= 0 && (abs(k) < delta || abs(k) == delta && f[m][k + 400] > sum)) {delta = abs(k);raw_delta = k;sum = f[m][k + 400];ansk = k;}}printf("Jury #%d\n", ++ kcase);printf("Best jury has value %d for prosecution and value %d for defence:\n", (sum - raw_delta) / 2, (sum + raw_delta) / 2);print(n, m, ansk);puts("\n"); }
}

Problem D. Proud Merchants(有顺序的 0/1 背包)

HDU 3466

给定 nnn 个物品,每个物品有个价格 pip_ipi​ , 价值 viv_ivi​,当手里的钱少于 qiq_iqi​ 时就不能购买这个物品了, 问给定 mmm 元,能够买到的最大价值是多少?

n≤500,m≤5000n \le 500,m \le 5000n≤500,m≤5000

Solution

购买物品有前提条件,显然是需要找到一个顺序的,我们可以使用贪心,利用扰动法找到这个顺序。

对于任意两个物品 a{pa,qa}a\{p_a, q_a\}a{pa​,qa​} 和 b{pb,qb}b\{p_b,q_b\}b{pb​,qb​} ,有种情况:

  • 先买 aaa,再买 bbb,即先支付 pap_apa​ 元购买 aaa,然后至少需要 qbq_bqb​ 元才能获得购买 bbb 的资格,具体是否购买由DP决定,因此至少需要拥有 pa+qbp_a + q_bpa​+qb​ 元。
  • 先买 bbb,再买 aaa,即先支付 pbp_bpb​ 元购买 bbb,然后至少需要 qaq_aqa​ 元才能获得购买 aaa 的资格,具体是否购买由DP决定,因此至少需要拥有 pb+qap_b + q_apb​+qa​ 元。

我们希望购买的物品付出代价尽可能的少,即令 pa+qb<pb+qap_a + q_b < p_b + q_apa​+qb​<pb​+qa​,显然此时我们应该先买 aaa,再买 bbb,即 qa−pa<qb−pbq_a - p_a < q_b - p_bqa​−pa​<qb​−pb​。

因此我们按照 qi−piq_i-p_iqi​−pi​ 从小到大的顺序进行DP转移即可。

Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 500 + 7, maxm = 5000 + 7;int n, m, s, t, k, ans;
int f[maxm];
struct node
{int p, q, v;
}a[maxn];int main()
{while(scanf("%d%d", &n, &m) != EOF) {memset(f, 0, sizeof f); for (int i = 1; i <= n; ++ i) scanf("%d%d%d", &a[i].p, &a[i].q, &a[i].v);sort(a + 1, a + 1 + n, [&](node a, node b) {return a.q - a.p < b.q - b.p;});for (int i = 1; i <= n; ++ i) {for (int j = m; j >= max(a[i].p, a[i].q); -- j) f[j] = max(f[j], f[j - a[i].p] + a[i].v);}int ans = 0;for (int j = 1; j <= m; ++ j)ans = max(ans, f[j]);cout << ans << '\n';}return 0;
}

Problem E. Bag Problem(搜索剪枝求解 0/1 背包)

HDU 3448

kkk 个物品中,最多选择 nnn 个,并且价值不能超过 mmm ,求能够达到的最大价值。

k≤40,m≤109k ≤ 40,m \le 10^9k≤40,m≤109

Solution

由于背包容量很大,但是物品个数很少,所以显然不能使用动态规划解决。k≤40k\le40k≤40,考虑爆搜。

每个物品均可选或者不选,直接爆搜最坏时间复杂度为O(240)O(2^{40})O(240) ,尝试加入一些剪枝优化。

首先我们搜索的时候,可以先将所有物品按照价值递减排序,然后记录后缀和,再进行搜索求解最优解 ans\mathrm {ans}ans。

考虑剪枝:

  1. 可行性剪枝: 若当前得到的总价值 value>m\mathrm{value} > mvalue>m,直接返回即可。

  2. 最优解剪枝: 若当前得到的总价值 value==m\mathrm{value} == mvalue==m,说明找到了最优解,直接返回即可。

  3. 最优性剪枝 1: 若当前得到的总价值 value\mathrm{value}value 加上剩余能够选取的 xxx 个最大价值的物品的总价值(利用后缀和可以 O(1)O(1)O(1) 得到)仍然小于 ans\mathrm{ans}ans,直接返回即可。

  4. 最优性剪枝 2: 若当前得到的总价值 value\mathrm{value}value 加上剩余能够选取的 xxx 个最大价值的物品的总价值(利用后缀和可以 O(1)O(1)O(1) 得到) ≤m\le m≤m,直接更新 ans\mathrm{ans}ans,然后直接返回即可。

经过上述四轮剪枝之后,时间复杂度将达到一个非常玄学的程度 ~

Code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int maxn = 40 + 7;
int n, m, s, t, k;
ll ans;
ll v[maxn];
ll suf[maxn];
ll val;void dfs(int now, int cnt, ll sum)//当前第 now 个物品,取了 cnt 个物品,总价值为 sum
{if(sum > m || cnt > n) return ;if(sum + suf[now] <= ans) return ;if(cnt + (k - now + 1) <= n && sum + suf[now] <= m) {sum += suf[now];ans = max(ans, sum);return ;}ans = max(ans, sum);/*dfs(now + 1, cnt + 1, sum + v[now]);dfs(now + 1, cnt, sum);*/for (int i = now; i <= k; ++ i)dfs(i + 1, cnt + 1, sum + v[i]);
}int main()
{while(scanf("%d%d", &n, &m) != EOF) { memset(suf, 0, sizeof suf);ans = 0;scanf("%d", &k);  for (int i = 1; i <= k; ++ i)scanf("%lld", &v[i]);sort(v + 1, v + 1 + k, [&](ll a, ll b){return a > b;});  for (int i = k; i >= 1; -- i)suf[i] = suf[i + 1] + v[i]; if(v[k] > m) {puts("0");continue;}  if(suf[1] - suf[n + 1] <= m) {cout << suf[1] - suf[n + 1] << '\n';continue;}dfs(1, 0, 0);cout << ans << '\n';}  return 0;
}

Problem F. 砝码称重

AcWing 3417

你有一架天平和 NNN 个砝码,这 NNN 个砝码重量依次是 W1,W2,⋅⋅⋅,WNW_1,W_2,⋅⋅⋅,W_NW1​,W2​,⋅⋅⋅,WN​。

请你计算一共可以称出多少种不同的正整数重量?

注意砝码可以放在天平两边。

1≤N≤1001≤N≤1001≤N≤100,NNN 个砝码总重不超过 10510^5105。

Solution

这里是一个天平,能称出来的重量为左右重量详减的绝对值。我们需要求出砝码能称出来的重量,所以我们需要维护重量 jjj 。

因此我们可以设 f[i,j]f[i, j]f[i,j] 表示从前 iii 个砝码中选择若干个,重量 jjj 是否能被称出来。显然对于一个砝码而言,有不选,选且放置在天平左端,选且放置在天平右端三种情况,有转移方程 :

f[i,j]=f[i−1][j]∣f[i−1][j+a[i]∣f[i−1][abs(j−a[i])]f[i, j] = f[i -1][j] \mid f[i -1][j + a[i]\mid f[i - 1][\mathrm {abs}(j - a[i])] f[i,j]=f[i−1][j]∣f[i−1][j+a[i]∣f[i−1][abs(j−a[i])]

初始化:f[0][0]=truef[0][0] = truef[0][0]=true

最后循环 jjj 统计答案即可。

时间复杂度: O(NM)O(NM)O(NM)

Code1

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 7, maxw = 1e5 + 7;
int n, m, s, t, k, ans;
int a[maxn];
int f[maxn][maxw];
int sum;int main()
{scanf("%d", &n);for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);f[0][0] = 1;for (int i = 1; i <= n; ++ i)  for (int j = maxw; j >= 0; -- j)  f[i][j] = f[i - 1][j] | f[i - 1][abs(j - a[i])] | f[i - 1][j + a[i]];     int ans = 0;for (int j = 1; j <= maxw; ++ j)if(f[n][j])ans ++ ;cout << ans << endl;return 0;
}

也可以直接利用 bitset ,O(n)O(n)O(n) 计算答案。

初始化 s[0]=1s[0] = 1s[0]=1,S |= S << a[i] 即天平左端放置砝码 a[i]a[i]a[i](左移 a[i]a[i]a[i] 就是加上 a[i]a[i]a[i] 嘛)。

最后减去不合法方案(重量 000)即可。

Code2

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 7, maxw = 1e5 + 7;
int n, m, s, t, k, ans;
int a[maxn];
bitset<maxw> S;int main()
{scanf("%d", &n);for (int i = 0; i < n; ++ i) scanf("%d", &a[i]);S[0] = 1;for (int i = 0; i < n; ++ i) S |= S << a[i];for (int i = 0; i < n; ++ i) S |= S >> a[i];cout << S.count() - 1 << '\n';return 0;
}

0x52.2 完全背包

Template

给定 NNN 种物品,其中第 iii 种物品的体积为 ViV_iVi​,价值为 WiW_iWi​,有无数个。有一个容积为 MMM 的背包,
求选择一些物品放入背包,使得物品的总体积不超过 M 的前提下,物品的价值总和最大,即背包不一定装满。

Solution

显然仍然是一个线性 DP 。

f[i,j]=max⁡{f[i−1][j]}f[i, j] = \max\{f[i - 1][j]\}f[i,j]=max{f[i−1][j]} 未选过第 iii 种物品
f[i,j]=max⁡{f[i,j−v[i]]+w[i]}f[i, j] = \max\{f[i, j - v[i]] + w[i]\}f[i,j]=max{f[i,j−v[i]]+w[i]} 从第 iii 种物品中选择一个

这里不需要保证 f[i]f[i]f[i] 一定是从 f[i−1]f[i - 1]f[i−1] 阶段转移过来,因为每个物品可以选择无限次,也就是说这里的 f[i]f[i]f[i] 可以从 f[i]f[i]f[i] 中转移过来,所以直接正序循环即可。

memset(f, 0xcf, sizeof f);
f[0] = 0;
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]);
int ans = 0;
for (int j = 0; j <= m; ++ j)ans = max(ans, f[j]);

Problem A. 自然数拆分

AcWing 279

给定一个自然数 NNN,要求把 NNN 拆成若干个正整数相加的形式,参与加法运算的数可以重复,求拆分的方案数 mod2147483648\mod 2147483648mod2147483648 的结果。
1≤N≤40001\le N \le 40001≤N≤4000

Solution

显然是完全背包模型求方案数,转移求和即可。
注意题目要求一定要拆分成若干个整数相加,即不能仅为 NNN 这一个数
但是 DP 的时候会计算一个数 NNN 的方案数,因此最后答案要减一。

Code

#include <bits/stdc++.h>
using namespace std;
using ll = long long;
const int N = 1e5 + 6;
const ll mod = 2147483648;
int n, m;
ll f[N];int main()
{scanf("%d", &n);f[0] = 1;for (int i = 1; i <= n; ++ i) for (int j = i; j <= n; ++ j) f[j] = (f[j] + f[j - i]) % mod;cout << (f[n] - 1 + mod) % mod << endl;return 0;
}

Problem B. CRB and His Birthday

HDU 5410

商店里有 nnn 种商品,第 iii 种商品的价格为 wiw_iwi​ 元,如果购买第 iii 种商品 xxx 件,花费 wi∗xw_i*xwi​∗x 元,并且可以获得 ai∗x+bia_i * x + b_iai​∗x+bi​ 颗糖果,问给定 mmm 元钱,求能够获得的最多糖果数。

n≤1000,m≤2000n \le 1000,m ≤ 2000n≤1000,m≤2000

Solution

看起来想像是一个完全背包,我们设 f[j]f[j]f[j] 表示前 iii 种商品中购买若干件,总花费为 jjj ,得到的最大糖果数。

显然有暴力转移方程:

f[j]=max⁡(f[i,j],f[i,j−wi×k]+ai×k+bi),1≤k≤jwi\begin{array}{c}f[j]=\max (f[i, j], f[i, j-w_i\times k]+a_i \times k+b_i),1 \leq k \leq \dfrac{j}{w_i}\\ \end{array} f[j]=max(f[i,j],f[i,j−wi​×k]+ai​×k+bi​),1≤k≤wi​j​​

显然时间复杂度是 O(nm2)O(nm^2)O(nm2),考虑优化。若将 bib_ibi​ 去掉,就是一个完全背吧的模板,所以我们考虑将 aia_iai​ 和 bib_ibi​ 分开,发现 bib_ibi​ 只有在第一次购买的时候才会获得,因此我们将其拆开:

设 f[j,1]f[j, 1]f[j,1] 表示前 iii 种商品中,购买第 iii 种商品,总花费为 jjj 能得到的最大的糖果数。

设 f[j,0]f[j, 0]f[j,0] 表示前 iii 种商品中,不买第 iii 件商品 ,总花费为 jjj ,得到的最大糖果数。
{f[j,1]=max⁡{f[j−wi,0]+ai+bi,f[j−wi,1]+ai}f[j,0]=max⁡{f[j,0],f[j,1]}\left\{\begin{array}{l}f[j,1] = \max\{f[j - w_i,0] + a_i + b_i, f[j - w_i,1] + a_i\}\\f[j, 0]=\max \{f[j,0], f[j,1]\}\end{array}\right. {f[j,1]=max{f[j−wi​,0]+ai​+bi​,f[j−wi​,1]+ai​}f[j,0]=max{f[j,0],f[j,1]}​

先转移 f[j,0f[j,0f[j,0,再使用 f[j,0]f[j,0]f[j,0] 转移 f[j,1]f[j,1]f[j,1] 即可。

Code

#include <bits/stdc++.h>
using namespace std;const int maxn = 1000 + 7, maxm = 2000 + 7;
int n, m, s, t, k, ans;
int f[maxm][2];
int a[maxn], b[maxn], w[maxn];void solve()
{scanf("%d%d", &m, &n);for (int i = 1; i <= n; ++ i) scanf("%d%d%d", &w[i], &a[i], &b[i]);memset(f, 0, sizeof f);for (int i = 1; i <= n; ++ i) {for (int j = 0; j <= m; ++ j)f[j][0] = max(f[j][0], f[j][1]);for (int j = w[i]; j <= m; ++ j)f[j][1] = max(f[j - w[i]][0] + a[i] + b[i], f[j - w[i]][1] + a[i]);}cout << max(f[m][1], f[m][0]) << endl;
}int main()
{scanf("%d", &t);while(t -- ) {solve();}return 0;
}

Problem C. Partial Tree(有个数限制的完全背包)

HDU 5534

对于 nnn个结点的树,给定 n−1n-1n−1 个数字 f(d)f(d)f(d),其中 ddd 代表树上结点的度数,求构造一棵树使得 ∑i=1nf(deg(i))\displaystyle \sum_{i=1}^{n} f( \mathrm{deg}(i) )i=1∑n​f(deg(i)) 最大 (deg(i)\mathrm {deg}(i)deg(i) 代表 结点 iii 的度数)。

n≤2000,1≤d<nn ≤ 2000,1 \le d < nn≤2000,1≤d<n

Solution

Code

Problem D. 付公主的背包(生成函数求解背包计数问题)

Luogu P4389

付公主有一个可爱的背包 qwq

这个背包最多可以装 10510^5105 大小的东西。付公主有 nnn 种商品,她要准备出摊了。 每种商品体积为 viv_ivi​ ,都有无限件。给定 mmm ,对于 s∈[1,m]s\in [1,m]s∈[1,m] ,请你回答用这些商品恰好装 sss 体积的方案数。

1≤n,m≤105,1≤vi≤m1\le n,m \le 10^5 ,1\le v_i \le m1≤n,m≤105,1≤vi​≤m

Solution

n,m≤105n,m\le 10^5n,m≤105,使用 O(nm)O(nm)O(nm) 的完全背包计数显然无法承受,考虑生成函数计数,背包计数问题实际上就是无标号的集合计数问题。

对于一个体积为 vvv 的物品,设它装满容量为 xxx 的背包的方案数序列为 Sv=[v∣x]S_{v}=[v|x]Sv​=[v∣x]

v=3v=3v=3 时:

S3={1,0,0,1,0,0,1,0,…}=1×x0+0×x1+0×x2+1×x3…x3S3={0,0,0,1,0,0,1,0,…}=0×x0+0×x1+0×x2+1×x3…S3−x3S3=1S3=11−x3S_3=\{1,0,0,1,0,0,1,0,\dots\}\\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =1\times x^0+0\times x^1+0\times x^2+1\times x^3\dots\\ x^3S_3=\{0,0,0,1,0,0,1,0,\dots\}\\ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ \ =0\times x^0+0\times x^1+0\times x^2+1\times x^3\dots\\ S_3-x^3S_3=1\\ S_3=\frac{1}{1-x^3} S3​={1,0,0,1,0,0,1,0,…}                       =1×x0+0×x1+0×x2+1×x3…x3S3​={0,0,0,1,0,0,1,0,…}                         =0×x0+0×x1+0×x2+1×x3…S3​−x3S3​=1S3​=1−x31​

即 Sv=11−xvS_v=\displaystyle\dfrac{1}{1-x^v}Sv​=1−xv1​

设题目中的恰好装 sss 体积的方案数的普通生成函数为 f(x)f(x)f(x)

显然有 f(x)=∏i=1n11−xvi\displaystyle f(x)=\prod_{i=1}^{n}\dfrac{1}{1-x^{v_i}}f(x)=i=1∏n​1−xvi​1​。

两边取对数:ln⁡f(x)=∑i=1nln⁡11−xvi\displaystyle\ln f(x)=\sum_{i=1}^{n}\ln\frac{1}{1-x^{v_i}}lnf(x)=i=1∑n​ln1−xvi​1​。

设 g(x)=ln⁡11−xkg(x)=\ln \cfrac{1}{1-x^k}g(x)=ln1−xk1​

g(x)=ln⁡11−xk=∫(ddxln⁡f)(x)dx=∫(f′(x)f(x))dx=∫((1−xk)f′(x))dx=∫((1−xk)∑i=1∞k⋅i⋅xki−1)dx=∫(∑i=1∞k⋅i⋅xki−1−∑i=1∞k⋅i⋅xki−1⋅xk)dx=∫(∑i=1∞k⋅i⋅xki−1−∑i=1∞k⋅(i−1)⋅xki−1)dx=∫(∑i=1∞k⋅xki−1)dx=∑i=1∞1ixki\begin{aligned}g(x)&=\ln \cfrac{1}{1-x^k}\\&=\int(\frac{\mathrm{d}}{\mathrm{d}x}\ln f)(x)\mathrm{d}x\\&=\int(\frac{f'(x)}{f(x)})\mathrm{d}x\\&=\int((1-x^k)f'(x))\mathrm{d}x\\&=\int((1-x^k)\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1})\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}-\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}\cdot x^k)\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot i\cdot x^{ki-1}-\sum_{i=1}^{\infty}k\cdot (i-1)\cdot x^{ki-1})\mathrm{d}x\\&=\int(\sum_{i=1}^{\infty}k\cdot x^{ki-1})\mathrm{d}x\\&=\sum_{i=1}^{\infty}\frac{1}{i}x^{ki}\end{aligned} g(x)​=ln1−xk1​=∫(dxd​lnf)(x)dx=∫(f(x)f′(x)​)dx=∫((1−xk)f′(x))dx=∫((1−xk)i=1∑∞​k⋅i⋅xki−1)dx=∫(i=1∑∞​k⋅i⋅xki−1−i=1∑∞​k⋅i⋅xki−1⋅xk)dx=∫(i=1∑∞​k⋅i⋅xki−1−i=1∑∞​k⋅(i−1)⋅xki−1)dx=∫(i=1∑∞​k⋅xki−1)dx=i=1∑∞​i1​xki​

即:ln⁡11−xk=∑i=1∞1ixik\displaystyle\ln\frac{1}{1-x^k}=\sum_{i=1}^{\infty}\frac{1}{i}x^{ik}ln1−xk1​=i=1∑∞​i1​xik

ln⁡f(x)=∑i=1n∑j=1∞1jxvij=∑k=1m∑j=1∞∑i=1n[vi=k]1ixkj\begin{aligned}\ln f(x)&=\sum_{i=1}^{n}\sum_{j=1}^{\infty}\frac{1}{j}x^{v_{i}j}\\&=\sum_{k=1}^{m}\sum_{j=1}^{\infty}\displaystyle\sum_{i=1}^{n}[v_i=k]\frac{1}{i}x^{kj}\end{aligned} lnf(x)​=i=1∑n​j=1∑∞​j1​xvi​j=k=1∑m​j=1∑∞​i=1∑n​[vi​=k]i1​xkj​

设 cntk\mathrm{cnt}_kcntk​ 为体积为 kkk 的物品的数量,可以在输入时预处理,由于总体积 s≤ms\le ms≤m ,我们只需要求 xxx 的前 mmm 项即可。则有:
ln⁡f(x)≡∑k=1m∑j=1⌊mk⌋cntk×1ixkj(modxm+1)\displaystyle\ln f(x)\equiv\sum_{k=1}^{m}\sum_{j=1}^{\left\lfloor\frac{m}{k}\right\rfloor}\mathrm{cnt}_k\times \frac{1}{i}x^{kj}\pmod{x^{m+1}} lnf(x)≡k=1∑m​j=1∑⌊km​⌋​cntk​×i1​xkj(modxm+1)

利用多项式科技在 O(mlog⁡m)O(m\log m)O(mlogm) 的复杂度下求解即可。

Code

0x52.3 多重背包

Template

给定 NNN 种物品,其中第 iii 种物品的体积为 ViV_iVi​,价值为 WiW_iWi​,并且有 CiC_iCi​ 个。
有一个容积为 MMM 的背包,要求选择若干个物品放入背包,使得物品总体积不超过 MMM 的前提下,物品的价值总和最大。

Solution

二进制拆分

时间复杂度 O(NMlog⁡Ci)O(NM\log C_i)O(NMlogCi​)

根据倍增算法,显然从 20,21,22⋯,2k2^0, 2^1, 2^2\cdots,2^k20,21,22⋯,2k 中任选若干个相加一定能凑出 0∼2k−10\sim 2^{k} - 10∼2k−1 之间的任意整数。
其实就是十进制的数在二进制下的表示,正确性显然。

我们只需要求出满足 20+21+⋯+2p≤Ci2^0 + 2^1+\cdots+2^p\le C_i20+21+⋯+2p≤Ci​ 的最大的整数 ppp ,设 Ri=Ci−20−21−⋯−2pR_i=C_i - 2^0-2^1-\cdots-2^pRi​=Ci​−20−21−⋯−2p
我们就可以把数量为 CiC_iCi​ 的第 iii 种物品拆成 p+2p+2p+2 个物品,体积分别为:20×Vi,21×Vi,⋯,2p×Vi,Ri×Vi2^0\times V_i, 2^1\times V_i,\cdots,2^p\times V_i,R_i\times V_i20×Vi​,21×Vi​,⋯,2p×Vi​,Ri​×Vi​
这 p+2p+2p+2 个物品可以凑成 0∼Ci×Vi0\sim C_i\times V_i0∼Ci​×Vi​ 之间所有 ViV_iVi​ 的倍数,且不超过 CiC_iCi​,即对应了原问题中的物品可用 0∼Ci0\sim C_i0∼Ci​ 次。

Code

#include <bits/stdc++.h>
using namespace std;const int N = 1e5 + 7;int n, m;
int v[N], w[N], cnt;
int f[N];int main()
{memset(f, 0xcf, sizeof f);f[0] = 0;scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++ i) {int a, b, c;scanf("%d%d%d", &a, &b, &c);for (int j = 1; j <= c; j <<= 1) {v[ ++ cnt] = j * a;w[cnt] = j * b;c -= j;}if(c)v[ ++ cnt] = c * a, w[cnt] = c * b; }for (int i = 1; i <= cnt; ++ i)for (int j = m; j >= v[i]; -- j)f[j] = max(f[j], f[j - v[i]] + w[i]);int ans  = 0;for (int j = 1; j <= m; ++ j)ans = max(ans, f[j]);cout << ans << endl; return 0;
}

单调队列优化

时间复杂度 O(NM)O(NM)O(NM)

Problem A. 硬币(贪心优化)

AcWing 281

给定 NNN 种硬币,其中第 iii 种硬币的面值为 AiA_iAi​,共有 CiC_iCi​ 个。

从中选出若干个硬币,把面值相加,若结果为 SSS,则称“面值 SSS 能被拼成”。

求 1∼M1\sim M1∼M 之间能被拼成的面值有多少个。

1≤N≤100,1≤M≤105,1≤Ai≤105,1≤Ci≤10001≤N≤100, 1≤M≤10^5, 1≤Ai≤10 ^5, 1≤Ci≤10001≤N≤100,1≤M≤105,1≤Ai≤105,1≤Ci≤1000

Solution

显然是多重背包,我们可以尝试使用二进制拆分求解答案。

我们设 f[j]f[j]f[j] 表示在前 iii 个硬币中能否拼出面值 jjj ,转移之后循环统计答案即可。

TLE Code

由于 y 总加强了数据,所有非 O(NM)O(NM)O(NM) 算法均无法通过,所以 O(NMlog⁡n)O(NM\log n)O(NMlogn) 的二进制拆分多重背包 T 了…

//对于第 i 种物品选择 x_i 个
#include <bits/stdc++.h>
using namespace std;const int N = 1e6 + 7;int n, m;
int v[N], w[N], cnt;
bool f[N];
int a[N], c[N];int main()
{  while(scanf("%d%d", &n, &m) != EOF && n + m) {memset(f, 0, sizeof f);f[0] = true;cnt = 0;for (int i = 1; i <= n; ++ i)scanf("%d", &a[i]);for (int i = 1; i <= n; ++ i)scanf("%d", &c[i]);for (int i = 1; i <= n; ++ i) { for (int j = 1; j <= c[i]; j <<= 1) {v[ ++ cnt] = j * a[i];c[i] -= j;}if(c[i])v[ ++ cnt] = c[i] * a[i]; }for (int i = 1; i <= cnt; ++ i)for (int j = m; j >= v[i]; -- j)f[j] |= f[j - v[i]];int ans = 0;for (int j = 1; j <= m; ++ j)ans += f[j];cout << ans << endl; }return 0;
}

我们可以使用单调队列优化多重背包 O(NM)O(NM)O(NM) 求解本题,但是可以考虑贪心优化。

由于本题仅关注 “可行性” 而非 “最优性” ,因此我们可以发现,若前 iii 种硬币能拼成面值 jjj ,那么只有两种可能的情况

  • 前 i−1i-1i−1 种硬币就能拼成面值 jjj ,即在阶段 iii 开始前,f[j] = true

  • 使用了第 iii 种硬币,即在第 iii 阶段的递推过程中,发现 f[j - a[i]] = true,使用一个第 iii 种硬币,使得 f[j] = true

因此我们可以考虑一种贪心策略:设 used[j] 表示在阶段 iii 下将 f[j] 变为 true至少需要使用多少枚第 iii 种硬币。

为了满足我们的贪心策略,我们应该尽量多的使用第 111 种情况,即:

  • f[j - a[i]]true ,若 f[j] 已经为 true,就不进行转移,并令 used[j] = 0

  • 当且仅当 f[j - a[i]] = truef[j] = false 且已经使用的第 iii 种硬币 used[j - a[i]] < c[i] 时,我们使用一个 iii 硬币使 f[j] 变为trueused[j] = used[j - a[i]] + 1

AC Code

#include <bits/stdc++.h>
using namespace std;
const int maxn = 100 + 7, maxm = 1e5 + 7;
int n, m, s, t, k, ans;
int a[maxn], c[maxn];
int f[maxm];
int used[maxm];int main()
{while(scanf("%d%d", &n, &m) != EOF && n + m) {memset(f, 0, sizeof f);ans = 0;for (int i = 1; i <= n; ++ i) scanf("%d", &a[i]);for (int i = 1; i <= n; ++ i) scanf("%d", &c[i]);f[0] = 1;for (int i = 1; i <= n; ++ i) {for (int j = 0; j <= m; ++ j)used[j] = 0;for (int j = a[i]; j <= m; ++ j) {  if(f[j - a[i]] && f[j] == false && used[j - a[i]] < c[i]) {used[j] = used[j - a[i]] = used[j - a[i]] + 1;f[j] = true, ans ++ ;}}} cout << ans << '\n';}return 0;
}

Problem B. The Fewest Coins (负权多重背包)

PKU 3260

你有 nnn 种不同的货币,第 iii 种货币的价值为 viv_ivi​ ,个数为 cic_ici​ 个, 现在你去商场里面买一件价值为 mmm 的商品,希望 花费的货币找回的货币 总和最少(假设商场的货币无限多)。

n≤100,vi≤120,0≤ci≤10000,m≤10000n \le 100 ,v_i\le 120,0 \le c_i \le 10000,m \le 10000n≤100,vi​≤120,0≤ci​≤10000,m≤10000

Solution

由于本题中涉及到找回的操作,所以我们引入 负容量 的概念。

Code

0x52.4 分组背包

Template 分组背包问题(分组背包,至多一个)

AcWing 9

有 NNN 组物品和一个容量是 VVV 的背包。

每组物品有若干个,同一组内的物品最多只能选一个
每件物品的体积是 vijv_{ij}vij​,价值是 wijw_{ij}wij​,其中 iii 是组号,jjj 是组内编号。

求解将哪些物品装入背包,可使物品总体积不超过背包容量,且总价值最大。

0<N,V≤100,0<Si≤100,0<vij,wij≤1000<N,V≤100, 0<S_i≤100, 0<v_{ij},w_{ij}≤1000<N,V≤100,0<Si​≤100,0<vij​,wij​≤100

Solution

每组至多选择一个

f[i,j]f[i, j]f[i,j] 表示从前 iii 组选出总体积为 jjj 的物品放入背包得到的最大价值和。

Code

#include <bits/stdc++.h>
using namespace std;
const int N = 100 + 7, INF = 0x3f3f3f3f;int n, m;
int f[N];
int c[N];
int v[N][N], w[N][N];int main()
{scanf("%d%d", &n, &m);for (int i = 1; i <= n; ++ i) {scanf("%d", &c[i]);for (int j = 1; j <= c[i]; ++ j) scanf("%d%d", &v[i][j], &w[i][j]);}memset(f, 0xcf, sizeof f);f[0] = 0;for (int i = 1; i <= n; ++ i) for (int j = m; j >= 0; -- j) for (int k = 1; k <= c[i]; ++ k) if(j >= v[i][k])f[j] = max(f[j], f[j - v[i][k]] + w[i][k]);int ans = 0;for (int j = 1; j <= m; ++ j)ans = max(ans, f[j]);cout << ans << '\n';return 0;
}

Problem A. I love sneakers! (分组背包,至少1个)

HDU 3033

有 nnn个物品和一个容量为 mmm的背包。这些物品被分成若干组,第 iii 个物品属于 gig_igi​ 组,容量是 cic_ici​,价值是 wiw_iwi​,现在需要选择一些物品放入背包,并且每组至少选择一个,总容量不能超过背包容量,求能够达到的物品的最大总价值。

n≤1000,m≤1000n ≤ 1000,m ≤ 1000n≤1000,m≤1000

Solution

Problem B. Balance (分组背包,正好1个)

PKU 1837

一架天平,CCC 个钩子,GGG 个砝码。每个钩子的范围 [−15,15][-15, 15][−15,15] ,每个砝码的重量范围是 [1,25][1, 25][1,25],问将每个砝码放上对应的钩子,最后使得天平平衡的方案数。

C≤20,G≤20C \le 20,G ≤ 20C≤20,G≤20

Solution

Problem C. AreYouBusy(混合分组背包,至少1个,至多1个,0/1背包)

HDU 3535

Problem D. Permutation (置换群 ,算数基本定理 ,分组背包,至多1个)

HDU 4345

将 SSS 分解成若干个数,并且得到它们的最小公倍数 xxx ,问 xxx 可能有多少种情况。

S≤1000S ≤ 1000S≤1000

Problem E. Least common multiple(算数基本定理 ,分组背包,至多1个)

HDU 3092

将 SSS 分解成若干个数,并且保证这些数的最小公倍数最大,求这个最大乘积模上 MMM 的值。

S≤3000S \le 3000S≤3000

Solution

显然 lcm\mathrm{lcm}lcm 最大,即将 SSS 拆成若干个互质的数。

我们就可以利用唯一分解定理, 每一个质数 ppp 以及 ppp 的若干次方 p2,p3…p^2,p^3\dotsp2,p3… 作为分组背包的一组,求至多选择一个,乘积为 SSS 的分组背包即可。

但是需要注意的一点是,我们这里要求取模,但是取模之后可能会导致 fff 的值在取 max⁡\maxmax 的时候得到不正确的答案,因此我们可以利用对数,将乘法转换为对数的加法,利用对数函数的单调性,我们设 f[i]f[i]f[i] 表示 iii 的对数能拼出的最大的 lcm\mathrm{lcm}lcm 即可。

0x52. 动态规划 - 背包(习题详解 × 19)相关推荐

  1. 状态压缩动态规划部分习题详解

    状态压缩动态规划部分习题详解 状压DP部分题目详解 状态压缩动态规划部分习题详解 简介 经典子集类问题 原子弹 最短路与状压DP结合 送礼物 P3959宝藏 旅游 经典网格类 铺地砖 一笔画 其他类型 ...

  2. 数据结构(C语言版) 第 八 章 排序 知识梳理 + 习题详解

    目录 一.归并排序 二.交换排序 1.快速排序 2.冒泡排序 三.插入排序 1.直接插入排序(基于顺序查找) 2.折半插入排序(基于折半查找) 3.希尔排序(基于逐趟缩小增量) 四.选择排序 0.直接 ...

  3. c语言线性表库函数大全,数据结构(C语言版)-线性表习题详解

    <数据结构(C语言版)-线性表习题详解>由会员分享,可在线阅读,更多相关<数据结构(C语言版)-线性表习题详解(23页珍藏版)>请在人人文库网上搜索. 1.数 据 结 构 ,线 ...

  4. c语言背包问题装字母,C语言动态规划之背包问题详解

    01背包问题 给定n种物品,和一个容量为C的背包,物品i的重量是w[i],其价值为v[i].问如何选择装入背包的物品,使得装入背包中的总价值最大?(面对每个武平,只能有选择拿取或者不拿两种选择,不能选 ...

  5. 数据结构(C语言版) 第 六 章 图 知识梳理 + 习题详解

    目录 一. 图的基本定义和术语 一.图的基本概念 1.度 2.连通 (1)连通图 (2)强连通/强连通图 3.回路 4.完全图 二.图的三种存储结构 1.邻接矩阵表示法 2.邻接表(链式)表示法 3. ...

  6. Python面对对象编程——结合面试谈谈封装、继承、多态,相关习题详解

    1.面向对象的三大特征 封装:属性和方法放到类内部,通过对象访问属性或者方法,隐藏功能的实现细节.当然还可以设置访问权限; 继承:子类需要复用父类里面的属性或者方法,当然子类还可以提供自己的属性和方法 ...

  7. 数学物理方法pdf_《数学物理方法》周明儒(第2版)补充材料与习题详解

    说明: 1.本资源为江苏师范大学 周明儒 教授所编著<数学物理方法>(第二版)配套电子资源: 2.由于Abook限制下载原版PDF,故本人高清截图保存整理为PDF格式供使用该书的同学使用, ...

  8. 微型计算机原理及应用程序题,郑学坚《微型计算机原理及应用》(第4版)笔记和课后习题详解...

    一.二进制数的相加 两个二进制数相加时,可以逐位相加.如二进制数可以写成 则从最右边第1位(即0权位)开始,逐位相加,其结果可以写成 其中各位是分别求出的 最后所得的和是 二.半加器电路 1要求 有两 ...

  9. 惯性力偶矩公式中j_理论力学(I)习题详解达朗贝尔原理.pdf

    您所在位置:网站首页 > 海量文档 &nbsp>&nbsp高等教育&nbsp>&nbsp习题/试题 理论力学(I)习题详解达朗贝尔原理.pdf15页 ...

最新文章

  1. LeetCode 965 Univalued Binary Tree--判断二叉树的所有节点的值是否相同--python,java解法
  2. protobuf 2.5.0 编译jar
  3. django-TDD
  4. sql server cvs 导入
  5. php数字补零的两种方法
  6. Spring Boot (4)---配置文件详解
  7. pat题解java,1039 到底买不买 (20分) Java题解 PAT (Basic Level) Practice (中文)- 巧妙开大数组减少代码量...
  8. GitLab CI的入门搭建
  9. Java查询对象中匹配元素_用LinkedList如何实现搜索指定对象的元素
  10. 用ado.net取数据库中table、column的信息
  11. 简单的Spring配置文件
  12. 视频教程-通俗易懂的全国计算机二级C语言真题精讲-C/C++
  13. Javashop连锁门店系统帮助企业快速搭建自己企业商城
  14. python 图像相似度;用0-1矩阵表示两幅图像的相似度
  15. C语言深度剖析——关键字sizeof、整型数据存储深入、数据类型取值范围深入
  16. iOS微信分享服务器设置,iOS 微信分享 universalLink
  17. 学习管理系统 LMS
  18. 解决Qt5屏幕翻转问题
  19. Android面试攻略
  20. AI:2020北京智源大会与五位图灵奖得主和100多位专家《共同探讨人工智能的下一个十年》——6月21日~6月24日的日程安排(实时更新,建议收藏)

热门文章

  1. 使用 Python 的基于边缘和基于区域的分割
  2. 干货 | YOLOV5 训练自动驾驶数据集,并转Tensorrt,收藏!
  3. 阿里、百度、字节跳动、京东、地平线等计算机视觉实习生面试经历分析,已成功上岸!...
  4. JavaWeb实现分页的四种方法
  5. 如何用 Python 和 Flask 建立部署一个 Facebook Messenger 机器人
  6. MySQL增量订阅消费组件Canal POC
  7. vue.js学习笔记 - 组件(二)
  8. Terracotta tc-config.xml配置说明(这个真的是转的)
  9. C++中访问类的私有数据成员的第三种方法
  10. mac redies install