多重集r-组合数与组合方案

news/2025/1/15 23:48:51/文章来源:https://www.cnblogs.com/Meth-nylon/p/18673370

多重集的r-组合是非常常见的组合问题, 但相关资料通常只给出组合数的计算, 却无法给出实际的方案, 下面将通过一个水果摆盘问题由简单到复杂逐步推导并给出最终的求组合数和组合方案的算法.

水果拼盘问题

假定有一次聚会需要准备一个水果拼盘, 其中拼盘中需要装入6个水果, 目前有4个苹果, 3个香蕉和6个桃子, 求有多少种不同组合, 并列举所有的方案.

用数学方式描述即为

存在一个多重集 \(S\), 其中元素允许重复, 比如本题中: $$S=[🍎, 🍎, 🍎, 🍎, 🍌, 🍌, 🍌, 🍑, 🍑, 🍑, 🍑, 🍑, 🍑]$$
本文为了简化写作以下形式(注意元素的个数写在乘号前): $$S=[4 \times🍎, 3 \times 🍌, 6 \times 🍑]$$

现在需从中选出 \(r\) 个元素组成一个组合, 求有多少不同的组合数.

水果无限多

首先推导水果无限多的情况, 由于拼盘容量仅有6个, 故只需水果有6个即等价于无限的情况.

隔板法

用隔板法可以简单推导:

  1. 准备好所有水果

\[\begin{align*} &🍎 🍎 🍎 🍎 🍎 🍎\\ &🍌 🍌 🍌 🍌 🍌 🍌\\ &🍑 🍑 🍑 🍑 🍑 🍑\\ \end{align*} \]

  1. 在苹果中插入一个隔板, 有0~6号位置共7种选择, 假定插在 \(k_1\) 位置, 取框中 \(k_1\) 水果共加入拼盘.

\[\begin{align*} \fbox{🍎 🍎}|&🍎 🍎 🍎 🍎\\ 🍌 🍌 &🍌 🍌 🍌 🍌\\ 🍑 🍑 &🍑 🍑 🍑 🍑\\ \end{align*} \]

  1. 在香蕉中插入一个隔板, 由于已经有了 \(k_1\) 个苹果, 所以只有0~6-\(k_1\) + 1种选择, 假定插在 \(k_2\) 位置.

\[\begin{align*} \fbox{🍎 🍎}|🍎 &🍎 🍎 🍎\\ \fbox{🍌 🍌 🍌}|&🍌 🍌 🍌\\ 🍑 🍑 🍑 &🍑 🍑 🍑\\ \end{align*} \]

  1. 最后由于只有三种水果, 故只有1种选择, 只能加入 \(6 - k_1 - k_2\) 个桃子

\[\begin{align*} \fbox{🍎 🍎}|🍎 &🍎 🍎 🍎\\ \fbox{🍌 🍌 🍌}|&🍌 🍌 🍌\\ \fbox{🍑}|🍑 🍑 &🍑 🍑 🍑\\ \end{align*} \]

综上可以总结出一个结论:
在一个有 \(k\) 种元素的多重集 $$S=[\infty·a_1, \infty·a_2, \infty·a_3, \dots, \infty·a_k]$$ 中选出 \(r\) 个元素共有$$\binom{r+k-1}{k-1}$$种组合. 在水果拼盘问题种有 \(\binom{6 + 3 - 1}{3 - 1} = 28\) 种组合.

该推导方式存在三个问题:

  1. 结论不直观, 从隔板法到组合数公式跨度略大
  2. 不能处理水果数目有限的情况
  3. 不能给出组合方案

后面会逐一解决以上三个问题.

动态规划法

通过 \(dp[i][j]\) 数组存放所有的组合方案, 其中 \(i\) 代表有有 \(i\) 种水果, \(j\) 代表果盘容量为 \(j\). 比如 \(dp[3][6]\) 即为3种水果选6个的所有组合方案.

  1. 建立dp数组
dp 0 1 2 3 4 5 6
0
1 (🍎)
2 (🍎, 🍌)
3 (🍎, 🍌, 🍑)
  1. 初始化dp数组
    \(j=0\) 时不选择水果, 为空组合, \(i=0\) 时没有水果组合无法组合, 即 \(dp[\_][0] = \varnothing\), \(dp[0][\_]\) 不存在(下划线"_"代表任意值), 特别的 \(dp[0][0]=\varnothing\)
dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (🍎) \(\varnothing\)
2 (🍎, 🍌) \(\varnothing\)
3 (🍎, 🍌, 🍑) \(\varnothing\)
  1. 处理dp[1][_]
    \(i=1\) 时有1种水果苹果, 那么取1个时只可以取1个苹果, 取2个时只能取2个苹果, 以此类推, 显然后一个方案必然由前一个方案加1个苹果得到, 即 \(dp[1][j] = dp[1][j-1] \cup [🍎]\)
dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] [5\(\times\)🍎] [6\(\times\)🍎]
2 (🍎, 🍌) \(\varnothing\)
3 (🍎, 🍌, 🍑) \(\varnothing\)
  1. 处理dp[2][_]

\(i=2\) 时有2种水果, 推广3中得结论有 \(dp[2][j] = dp[2][j-1] \cup [🍌]\), 同时 \(dp[2][j]\) 上一行 \(dp[1][j]\) 的方案也是可行的, 故有 \(dp[2][j] = (dp[2][j-1] \cup [🍌]) + dp[1][j]\)

dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] [5\(\times\)🍎] [6\(\times\)🍎]
2 (🍎, 🍌) \(\varnothing\) [🍌][🍎] [🍌🍌]
[🍌🍎]
[🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[4\(\times\)🍌]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
[5\(\times\)🍌]
[4\(\times\)🍌,🍎]
[🍌🍌🍌🍎🍎]
[🍌🍌🍎🍎🍎]
[🍌,4\(\times\)🍎]
[5\(\times\)🍎]
[6\(\times\)🍌]
[5\(\times\)🍌,🍎]
[4\(\times\)🍌,🍎🍎]
[🍌🍌🍌🍎🍎🍎]
[🍌🍌,4\(\times\)🍎]
[🍌,5\(\times\)🍎]
[6\(\times\)🍎]
3 (🍎, 🍌, 🍑) \(\varnothing\)
  1. 处理剩余情况
    由4的结论推广得到 \(dp[i][j] = (dp[i][j-1] \cup [第i种水果]) + dp[i-1][j]\), 基于此我们完成整个 \(dp\) 数组 (部分项目过多, 不再列举)
dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] [5\(\times\)🍎] [6\(\times\)🍎]
2 (🍎, 🍌) \(\varnothing\) [🍌][🍎] [🍌🍌]
[🍌🍎]
[🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[4\(\times\)🍌]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
[5\(\times\)🍌]
[4\(\times\)🍌,🍎]
[🍌🍌🍌🍎🍎]
[🍌🍌🍎🍎🍎]
[🍌,4\(\times\)🍎]
[5\(\times\)🍎]
[6\(\times\)🍌]
[5\(\times\)🍌,🍎]
[4\(\times\)🍌,🍎🍎]
[🍌🍌🍌🍎🍎🍎]
[🍌🍌,4\(\times\)🍎]
[🍌,5\(\times\)🍎]
[6\(\times\)🍎]
3 (🍎, 🍌, 🍑) \(\varnothing\) [🍑][🍌][🍎] [🍑🍑]
[🍑🍌]
[🍑🍎]
[🍌🍌]
[🍌🍎]
[🍎🍎]
[🍑🍑🍑]
[🍑🍑🍌]
[🍑🍑🍎]
[🍑🍌🍌]
[🍑🍌🍎]
[🍑🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[4\(\times\)🍑]
[🍑🍑🍑🍌]
[🍑🍑🍑🍎]
[🍑🍑🍌🍌]
[🍑🍑🍌🍎]
[🍑🍑🍎🍎]
[🍑🍌🍌🍌]
[🍑🍌🍌🍎]
[🍑🍌🍎🍎]
[🍑🍎🍎🍎]
[4\(\times\)🍌]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
\(\dots\) \(\dots\)

基于对 \(dp\) 数组的逐层推导, 我们得到如下的动态转移方程:

\[dp[i][j] = \begin{cases} \varnothing & \text{if }j = 0 \\ N/A & \text{if } i = 0 \text{ and } j \ne 0 \\ dp[i][j-1]\cup [f_i] + dp[i-1][j] & \text{else} \end{cases} \]

其中 \(f_i\) 为第i层出现的水果

如果单纯记录组合数而不必得到方案, 则同样易得动态转移方程

\[dp[i][j] = \begin{cases} 1 & \text{if }j = 0 \\ 0 & \text{if } i = 0 \text{ and } j \ne 0 \\ dp[i][j-1] + dp[i-1][j] & \text{else} \end{cases} \]

如此可得到无限水果下的组合数 \(dp\) 数组

dp 0 1 2 3 4 5 6
0 1 0 0 0 0 0 0
1 1 1 1 1 1 1 1
2 1 2 3 4 5 6 7
3 1 3 6 10 15 21 28

可以注意到 \(dp\) 数组构成了一个杨辉三角, 由杨辉三角通项公式易得无限水果条件下的摆盘问题解为:

\[\binom{6 + 3 - 1}{3 - 1} = 28 \]

通过 \(dp\) 数组法不仅能够推导出组合数公式, 通过集合运算给出了所有组合的具体方案

水果有限

水果有限时组合方案必然是无限时的子集, 所以需要通过一些方法减去不可行的方案, 从前文的动态转移方程中发现 \(dp[i][j-1]\cup [f_i]\) 这步骤不一定可行, 因为当 \(f_i\) 水果数目不足时不可以继续加入, 所以重点就在于处理该过程.

动态规划法

同样采用动态规划法推导组合方案:

  1. 初始化dp数组
    显然有

\[dp[i][j] = \begin{cases} \varnothing & \text{if }j = 0 \\ N/A & \text{if } i = 0 \text{ and } j \ne 0\end{cases} \]

dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (4\(\times\)🍎) \(\varnothing\)
2 (4\(\times\)🍎, 3\(\times\)🍌) \(\varnothing\)
3 (4\(\times\)🍎, 3\(\times\)🍌, 6\(\times\)🍑) \(\varnothing\)
  1. 处理dp[1][_]
    利用公式 \(dp[i][j] = (dp[i][j-1] \cup [🍎]) + dp[i-1][j]\), 显然苹果数目只够填满1~4格, \(j>4\) 的情况开始特殊处理.
dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (4\(\times\)🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] N/A N/A
2 (4\(\times\)🍎, 3\(\times\)🍌) \(\varnothing\)
3 (4\(\times\)🍎, 3\(\times\)🍌, 6\(\times\)🍑) \(\varnothing\)
  1. 处理dp[2][_]
    利用公式 \(dp[i][j] = (dp[i][j-1] \cup [🍌]) + dp[i-1][j]\), 香蕉同样存在不足的情况, \(j>3\) 的情况开始特殊处理.
    \(dp[2][4]\) 中香蕉开始出现不足, 此时需要删除最开始的第1个组合;
    \(dp[2][4]\) 删除了元素的基础上, dp[2][5]还要删除第1个组合;
    \(dp[2][6]\) 同样需要删除第1个组合.

    删除元素是因为其前3格把所有香蕉都用了, 所以必须删除部分元素.

    \(dp[2][1]\) 开始有1个组合使用香蕉, 所以必须删除1个 \(dp[2][4]\) 元素
    \(dp[2][2]\) 开始有2个组合使用香蕉, 所以必须删除2个 \(dp[2][5]\) 元素, 由于 \(dp[2][4]\) 已经删除了1个, 所以 \(dp[2][5]\) 实际只要删除1个.
    \(dp[2][3]\) 开始有3个组合使用香蕉, 所以必须删除3个 \(dp[2][6]\) 元素, 由于 \(dp[2][5]\) 已经删除了2个, 所以 \(dp[2][6]\) 实际只要删除1个.

    同时根据前文组合数递推式$$dp[i][j-3] = dp[i][j-1-3] + dp[i-1][j-3]$$经过化简可以推知删除元素的个数恰好等于 $$dp[i-1][j-1-3]$$中的组合数, 这就是为什么 \(dp[2][4]\) 需要删除 \(card(dp[2-1][4-1-3]) = card(dp[1][0]) = 1\) 个元素(空集也是一种组合); 同理 \(dp[2][5]\) 需要删除 \(card(dp[1][1]) = 1\) 个元素, 以此类推 (这部分推导因为过于复杂, 省略了用容斥原理展开并化简的过程, 有余力的读者可以尝试推导).

dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (4\(\times\)🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] N/A N/A
2 (4\(\times\)🍎, 3\(\times\)🍌) \(\varnothing\) [🍌][🍎] [🍌🍌]
[🍌🍎]
[🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[🍌🍌🍌🍌]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
[🍌🍌🍌🍌🍎]
[🍌🍌🍌🍎🍎]
[🍌🍌🍎🍎🍎]
[🍌,4\(\times\)🍎]
[🍌🍌🍌🍌🍎🍎]
[🍌🍌🍌🍎🍎🍎]
[🍌🍌,4\(\times\)🍎]
3 (4\(\times\)🍎, 3\(\times\)🍌, 6\(\times\)🍑) \(\varnothing\)
  1. 处理dp[3][_]
    由3得到新的转移方程推知 $$dp[i][j] = (dp[i][j-1] \cup [🍌] 舍去最初card(dp[i-1][j- 1 - \text{amount of }f_i])个组合) + dp[i-1][j]$$用这个公式可以推出 \(dp[3]\) 行 (由于 \(\text{amount of }🍑 = 6\) 所以实际不会删除任何组合).
dp 0 1 2 3 4 5 6
0 \(\varnothing\) N/A N/A N/A N/A N/A N/A
1 (4\(\times\)🍎) \(\varnothing\) [🍎] [🍎🍎] [🍎🍎🍎] [4\(\times\)🍎] N/A N/A
2 (4\(\times\)🍎, 3\(\times\)🍌) \(\varnothing\) [🍌][🍎] [🍌🍌]
[🍌🍎]
[🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
[🍌🍌🍌🍎🍎]
[🍌🍌🍎🍎🍎]
[🍌,4\(\times\)🍎]
[🍌🍌🍌🍎🍎🍎]
[🍌🍌,4\(\times\)🍎]
3 (4\(\times\)🍎, 3\(\times\)🍌, 6\(\times\)🍑) \(\varnothing\) [🍑][🍌][🍎] [🍑🍑]
[🍑🍌]
[🍑🍎]
[🍌🍌]
[🍌🍎]
[🍎🍎]
[🍑🍑🍑]
[🍑🍑🍌]
[🍑🍑🍎]
[🍑🍌🍌]
[🍑🍌🍎]
[🍑🍎🍎]
[🍌🍌🍌]
[🍌🍌🍎]
[🍌🍎🍎]
[🍎🍎🍎]
[4\(\times\)🍑]
[🍑🍑🍑🍌]
[🍑🍑🍑🍎]
[🍑🍑🍌🍌]
[🍑🍑🍌🍎]
[🍑🍑🍎🍎]
[🍑🍌🍌🍌]
[🍑🍌🍌🍎]
[🍑🍌🍎🍎]
[🍑🍎🍎🍎]
[🍌🍌🍌🍎]
[🍌🍌🍎🍎]
[🍌🍎🍎🍎]
[4\(\times\)🍎]
[5\(\times\)🍑]
[4\(\times\)🍑,🍌]
[4\(\times\)🍑,🍎]
[🍑🍑🍑🍌🍌]
[🍑🍑🍑🍌🍎]
[🍑🍑🍑🍎🍎]
[🍑🍑🍌🍌🍌]
[🍑🍑🍌🍌🍎]
[🍑🍑🍌🍎🍎]
[🍑🍑🍎🍎🍎]
[🍑🍌🍌🍌🍎]
[🍑🍌🍌🍎🍎]
[🍑🍌🍎🍎🍎]
[🍑,4\(\times\)🍎]
[🍌🍌🍌🍎🍎]
[🍌🍌🍎🍎🍎]
[🍌,4\(\times\)🍎]
[6\(\times\)🍑]
[5\(\times\)🍑,🍌]
[5\(\times\)🍑,🍎]
[4\(\times\)🍑,🍌🍌]
[4\(\times\)🍑,🍌🍎]
[4\(\times\)🍑,🍎🍎]
[🍑🍑🍑🍌🍌🍌]
[🍑🍑🍑🍌🍌🍎]
[🍑🍑🍑🍌🍎🍎]
[🍑🍑🍑🍎🍎🍎]
[🍑🍑🍌🍌🍌🍎]
[🍑🍑🍌🍌🍎🍎]
[🍑🍑🍌🍎🍎🍎]
[🍑🍑,4\(\times\)🍎]
[🍑🍌🍌🍌🍎🍎]
[🍑🍌🍌🍎🍎🍎]
[🍑🍌,4\(\times\)🍎]
[🍌🍌🍌🍎🍎🍎]
[🍌🍌,4\(\times\)🍎]

基于对dp数组的逐层推导, 我们得到如下的动态转移方程

\[dp[i][j] = \begin{cases} \varnothing & \text{if }j = 0 \\ N/A & \text{if } i = 0 \text{ and } j \ne 0 \\ (dp[i][j-1] \cup [f_i] 舍去最初 card(dp[i-1][j- 1-\text{amount of }f_i])个组合) + dp[i-1][j] & \text{else} \end{cases} \]

其中 \(f_i\) 为第i层出现的水果

如果单纯记录组合数而不必得到方案, 则同样易得动态转移方程

\[dp[i][j] = \begin{cases} 1 & \text{if }j = 0 \\ 0 & \text{if } i = 0 \text{ and } j \ne 0 \\ dp[i][j-1] - dp[i-1][j-1] + dp[i-1][j-1-\text{amount of }f_i] & \text{else} \end{cases} \]

如此可得到有限水果下的方案数dp数组

dp 0 1 2 3 4 5 6
0 1 0 0 0 0 0 0
1(4) 1 1 1 1 1 0 0
2(3) 1 2 3 4 4 3 2
3(5) 1 3 6 10 14 17 19

代码实现

下面用rust代码实现列举出所有中的r-组合方案

use std::fmt::Display;fn main() {let fruit_amount = [4, 3, 6];let fruit_kind = [Fruit::Apple, Fruit::Banana, Fruit::Peach];// use amount[] and kind[] replace S = [4*Apple, 3*Banana, 6*Peach]let plans: DPCell<Fruit> = r_combination_of_multiset(&fruit_amount, &fruit_kind, 6);for plan in plans.iter() {print!("[");for fruit in plan.iter() {print!("{}", fruit);}println!("]");}println!("there are {} plans", plans.len());
}type MultiSet<T> = Vec<T>;
type DPCell<T> = Vec<MultiSet<T>>;
type DPMatrix<T> = Vec<Vec<DPCell<T>>>;#[derive(Clone, Copy)]
enum Fruit {Apple,Banana,Peach,
}fn r_combination_of_multiset<T: Clone>(amount: &[usize], kind: &[T], r: usize) -> DPCell<T> {let amount: Vec<usize> = [&[0], amount].concat();let row_count = amount.len();let col_count = r + 1;let mut combinations: DPMatrix<T> = Vec::with_capacity(row_count);// dp initfor _ in 0..row_count {let mut row = Vec::with_capacity(col_count);for _ in 0..col_count {row.push(DPCell::new());}combinations.push(row);}for row in combinations.iter_mut() {row[0].push(vec![]);}// dp[i][j] += dp'[i][j-1] cup [i] skip card(dp[i-1][j-1-amount[i]]) + dp[i-1][j]for i in 1..row_count {for j in 1..col_count {let up = &combinations.clone()[i - 1][j];let left = &combinations.clone()[i][j - 1];let skip = if amount[i] < j {combinations.clone()[i - 1][j - 1 - amount[i]].len()} else {0};let current = &mut combinations[i][j];// dp[i][j] += dp'[i][j-1] cup [i] skip card(dp[i-1][j-1-amount[i]])add_left(current, left, kind[i - 1].clone(), skip);// dp[i][j] += dp[i-1][j]add_above(current, up);}}combinations.last().unwrap().last().unwrap().to_vec()
}fn add_left<T: Clone>(current: &mut DPCell<T>, left: &DPCell<T>, element_to_add: T, skip: usize) {for set_in_left in left.clone().iter_mut().skip(skip) {set_in_left.push(element_to_add.clone());current.push(set_in_left.to_vec());}
}fn add_above<T: Clone>(current: &mut DPCell<T>, above: &DPCell<T>) {for multiset in above.iter() {current.push(multiset.clone());}
}impl Display for Fruit {fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {match self {Self::Apple => write!(f, "🍎"),Self::Banana => write!(f, "🍌"),Self::Peach => write!(f, "🍑"),}}
}

运行得到

[🍑🍑🍑🍑🍑🍑]
[🍌🍑🍑🍑🍑🍑]
[🍎🍑🍑🍑🍑🍑]
[🍌🍌🍑🍑🍑🍑]
[🍎🍌🍑🍑🍑🍑]
[🍎🍎🍑🍑🍑🍑]
[🍌🍌🍌🍑🍑🍑]
[🍎🍌🍌🍑🍑🍑]
[🍎🍎🍌🍑🍑🍑]
[🍎🍎🍎🍑🍑🍑]
[🍎🍌🍌🍌🍑🍑]
[🍎🍎🍌🍌🍑🍑]
[🍎🍎🍎🍌🍑🍑]
[🍎🍎🍎🍎🍑🍑]
[🍎🍎🍌🍌🍌🍑]
[🍎🍎🍎🍌🍌🍑]
[🍎🍎🍎🍎🍌🍑]
[🍎🍎🍎🍌🍌🍌]
[🍎🍎🍎🍎🍌🍌]
there are 19 plans

基于以上代码简单修改即可得到无限水果组合方案以及组合数算法, 请读者自行编写. 注意由于涉及到删除集合中前若干元素的操作, 所以要求集合有序, 本文代码中使用Vec代替Set操作.

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/869851.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

ShellCheck工具:帮你发现Shell脚本安全隐患

作为一名运维工程师,你是否经常为Shell脚本中的各种隐藏bug而头疼?今天我要向大家推荐一个堪称"神器"的工具 - ShellCheck。它就像一位经验丰富的Shell编程导师,能够精准地发现你的脚本中的各种潜在问题,并给出专业的改进建议。它有多强? 想象一下,你有一位经验超过…

1.C++基础入门

C++基础入门。C++基础入门 1 C++初识 1.1 第一个C++程序 编写一个C++程序总共分为4个步骤创建项目 创建文件 编写代码 运行程序1.1.1 创建项目 ​ Visual Studio是我们用来编写C++程序的主要工具,我们先将它打开1.1.2 创建文件 右键源文件,选择添加->新建项给C++文件起个…

【Java开发】实现 License 认证(只校验有效期)

一、License介绍 License也就是版权许可证书,一般用于收费软件给付费用户提供的访问许可证明 1.1 应用场景应用部署在客户的内网环境 这种情况开发者无法控制客户的网络环境,也不能保证应用所在服务器可以访问外网 因此通常的做法是使用服务器许可文件,在应用启动的时候加载…

Proj CJI Paper Reading: AdaPPA: Adaptive Position Pre-Fill Jailbreak Attack Approach Targeting LLMs

AbstractBackground: 目前的jailbreak mutator方式更集中在语义level,更容易被防御措施检查到 本文: AdaPPA (Adaptive Position Pre-Filled Jailbreak Attack) Task: adaptive position pre-fill jailbreak attack approach Method: 利用模型的instruction following能力,先…

【Java安全】浅谈内存马

一、内存马概述1.1 内存马产生的背景1.2 Java内存马的基本原理1.3 Java内存马的类型1.4 Java内存马的使用场景二、内存马注入实战演示2.1 JSP注入Filter内存马2.2 Fastjson反序列化注入内存马2.3 注入Agent内存马三、内存马的检测与防御3.1 内存马定位排查思路3.2 工具查杀3.3 …

Diary - 2025.01.15

pkuwc 烂完了,😭😭😭其实是 pkuwc2024 的东西。 Day 0 坐飞机坐飞机,嘟嘟嘟。 大飞机!!!!!!!! 我觉得最厉害的是这个飞机有 3D 地图啊,太帅了!!!但是比较悲伤的是我直到要到了才知道,前面都在看 B 站缓存的视频😭。 感觉,太美丽了杭州!!! 坐飞机的时…

floor_plan_meshproject增加角度正则损失

数据结构 data.x #(128, 16) 16 = triangles(9) + confidence(7) """ 每个元素 [x1, y1, z1, x2, y2, z2, x3, y3, z3, c_v1, c_v2, c_v3, c_e1, c_e2, c_e3, c_f] """ data.y #(128)encoded_x #(128, 576) encoded_x_conv # (2, 96, 576) …

2025.1.15 html基础

学习了html的基础知识,包括:n越大,字体越小换行标签表示一个完整的段落水平线标签链接: 内容 例如: <! --a页面-->这是A页面。<! --b页面-->这是B页面。在浏览器中点击“这是A页面”,会跳转到b页面。

位图有关的格式信息

GetObject(hBitmap, sizeof(BITMAP), (LPSTR)&bmp); 获取 HBITMAP 句柄包含的位图信息结构,不包含像素数据内容。 typedef struct tagBITMAP {   LONG bmType; // 位图类型,必须为 0   LONG bmWidth; // 位图宽度(以像素为单位) …

Centos7.9安装kerberos

Centos7.9安装kerberos@目录一、背景二、Kerberos安装部署2.1kerberos服务端必要软件安装2.2配置krb5.conf2.3配置kdc.conf2.4配置kadm5.acl2.5创建Kerberos数据库2.6启动Kerberos服务2.7创建Kerberos管理员principal2.8客户端安装kerberos2.9Kerberos功能验证本人其他相关文章…

并发编程 - 初识线程

线程是操作系统单独执行任务的最小单元,分前台和后台,有优先级,经历多个状态。C#可设置线程优先级和类型,控制线程状态的方法有Start、Sleep等,但Suspend和Abort已被弃用。多线程编程需通过同步机制控制线程执行。01、什么是线程? 要深刻理解什么是线程,就需要了解计算机…