组合数学
阅读数:458 评论数:0
跳转到新版页面分类
数学
正文
一、排列与组合
(1)加法法则(Sum Rule)
如果有两个互斥的任务 A 和 B,任务 A 有 $n$ 种方法完成,任务 B 有 $m$ 种方法完成,那么完成任务 A 或任务 B 的方法总数是 $n + m$ 种。
换句话说,如果有一个任务可以通过两个互不相交(互斥)的途径之一来完成,则完成该任务的总方法数是通过每一个途径的方法数之和。
(2)乘法法则(Product Rule)
如果一个任务可以被分解为两个连续的步骤 A 和 B,步骤 A 有 $n$ 种方法完成,对于步骤 A 的每一种完成方法,步骤 B 都有 $m$ 种方法完成,则完成整个任务的方法总数是 $n \times m$ 种。
换句话说,如果一个任务可以分解为两个顺序的阶段,并且第二个阶段的执行方式数不依赖于第一阶段的具体执行方式,则完成该任务的总方法数是两个阶段的方法数的乘积。
给定两个集合 $A$ 和 $B$,如果存在一个函数 $f : A \rightarrow B$,使得对于每个 $a \in A$ 都有一个唯一的 $b \in B$ 与之对应,并且对于每个 $b \in B$ 也有一个唯一的 $a \in A$ 与之对应,那么我们说 $A$ 和 $B$ 之间存在一一对应关系。这样的函数 $f$ 被称为双射。
(1)排列(Permutations)
排列关注的是对象的顺序。当顺序重要时,我们使用排列的概念来计算可能的方式数。
**公式**:从 $n$ 个不同元素中取出 $k$ 个元素进行排列的方式数,记作 $P(n, k)$ 或 $^nP_k$,计算公式为:
$$
P(n, k) = \frac{n!}{(n-k)!}
$$
其中 $n!$($n$ 的阶乘)是从 1 到 $n$ 的所有正整数的乘积。
(2)组合(Combinations)
组合则不考虑对象的顺序。当问题中的选择不考虑顺序时,我们使用组合的概念来计算可能的方式数。
**公式**:从 $n$ 个不同元素中取出 $k$ 个元素的组合方式数,记作 $C(n, k)$ 或 $\binom{n}{k}$,计算公式为:
$$
C(n, k) = \frac{P(n, k)}{k!} = \frac{n!}{k!(n-k)!}
$$
(1)无区别圆周排列
当圆周排列中的位置是完全相同的,即通过旋转可以得到相同的排列时,我们使用无区别圆周排列的计算方法。在这种情况下,从 $n$ 个不同对象中形成圆周排列的方式数为 $(n - 1)!$。
**原因**:首先固定一个对象作为参照点,剩下的 $(n-1)$ 个对象有 $(n-1)!$ 种排列方式。由于圆周排列可以旋转,所以固定一个对象不改变排列的本质。
**示例**:如果有 5 个人围坐在一张圆桌周围,那么不考虑座位的不同,排列方式数为 $(5-1)! = 4! = 24$ 种。
(2)有区别圆周排列
如果圆周上的某些位置是有区别的,例如,桌子上有一个明显的头席或者圆环上有一个标记点,那么这种情况下的圆周排列就不能简单通过旋转来得到相同的排列。在这种情况下,圆周排列的计算方式与线性排列相同,即 $n!$。
(3)镜像问题
在某些情况下,如果圆周排列中的镜像排列也被认为是等价的(即顺时针和逆时针排列被视为相同),那么我们还需要对排列数进行额外的除法操作。对于没有重复对象的 $n$ 个对象的圆周排列,考虑镜像后的排列方式数是 $(n - 1)! / 2$。
**示例**:如果有 5 个不同颜色的珠子要串成一个项链,那么考虑镜像排列相同,排列方式数为 $(5-1)! / 2 = 4! / 2 = 12$ 种。
要根据给定的序号生成对应的排列,可以使用以下步骤:
- **初始化**:确定集合的大小$n$和要找的排列的序号$k$(通常从$0$开始计数)。
- **计算阶乘**:预先计算$0!$到$(n-1)!$的阶乘值,用于后续计算。
- **生成排列**:
- 创建一个列表,初始化为$[1, 2, \ldots, n]$。
- 对于$i$从$0$到$n-1$:
- 计算$d_i = \lfloor k / (n-i)! \rfloor$,这是当前位置的数字的索引。
- 从列表中选择并移除索引为$d_i$的元素,并将其添加到排列中。
- 更新$k$为$k \mod (n-i)!$。
假设我们有一个三元素的集合$\{1, 2, 3\}$,我们想要生成序号为$3$的排列。
- **计算阶乘**:$0! = 1$, $1! = 1$, $2! = 2$。
- **生成排列**:
- 当$i=0$时,$k = 3$,$d_0 = \lfloor 3 / 2! \rfloor = 1$,选择并移除列表中索引为$1$的元素($2$),更新$k = 3 \mod 2 = 1$。
- 当$i=1$时,$k = 1$,$d_1 = \lfloor 1 / 1! \rfloor = 1$,选择并移除列表中索引为$1$的元素($3$),更新$k = 1 \mod 1 = 0$。
- 当$i=2$时,只剩下一个元素($1$),直接添加到排列中。
这里是使用字典序法生成排列的步骤:
- **开始**:从最小的排列开始,即元素按升序排列(例如,对于集合 $\{1, 2, 3\}$,最小的排列是 $[1, 2, 3]$)。
- **查找下一个排列**:
- 从排列的最后一个元素向前查找,找到第一个满足 $a[i] < a[i+1]$ 的位置 $i$。如果不存在这样的位置,则所有排列已经生成,算法结束。
- 在排列的尾部(即位置 $i$ 之后的所有元素)查找最小的元素 $a[j]$,满足 $a[j] > a[i]$。
- 交换元素 $a[i]$ 和 $a[j]$。
- 反转位置 $i+1$ 到排列末尾的所有元素。
- **输出排列**:当前排列就是下一个字典序排列。
- **重复**:重复步骤2,直到无法找到下一个排列。
假设我们有排列 $[1, 2, 3]$,我们想要找到它的下一个字典序排列。
- **查找位置 $i$**:从后向前查找,$2 < 3$,所以 $i=1$。
- **查找位置 $j$**:在 $[3]$ 中查找大于 $2$ 的最小元素,所以 $j=2$。
- **交换 $a[i]$ 和 $a[j]$**:交换 $2$ 和 $3$,排列变为 $[1, 3, 2]$。
- **反转 $i+1$ 到末尾的元素**:因为 $i+1$ 到末尾的元素只有 $2$,所以反转后排列不变,仍为 $[1, 3, 2]$。
所以,排列 $[1, 2, 3]$ 的下一个字典序排列是 $[1, 3, 2]$。
这种方法的核心思想是通过交换两个相邻元素来逐步生成所有的排列。
function permute(array, start):
if start == length(array):
print(array)
return
for i from start to length(array):
swap(array[start], array[i]) // 交换当前元素与后续元素
permute(array, start + 1) // 对剩余的元素进行递归排列
swap(array[start], array[i]) // 交换回来,以便下一次交换
在数学上,这个问题可以表述为:有 \( n \) 种不同的物品,允许重复选择,要选取 \( k \) 个出来(每种物品可以选任意次或不选)。求一共有多少种不同的选法。
推导过程:
假设我们有 \( k \) 个不可区分的物品(可以想象成 \( k \) 个星号 *),我们要将这些物品放入 \( n \) 个可区分的盒子中(可以想象成 \( n-1 \) 个隔板 | 将空间分隔成 \( n \) 部分)。每个盒子可以为空,或者包含一个或多个物品。
为了找出所有可能的放置方式,我们可以将问题视为在 \( k \) 个物品和 \( n-1 \) 个隔板的序列中找到所有可能的排列。
现在,我们把物品和隔板一起看作是一个序列。这个序列总共有 \( k + n - 1 \) 个位置,其中 \( k \) 个位置将被物品占据,剩下的 \( n - 1 \) 个位置被隔板占据。因此,问题转化为从 \( k + n - 1 \) 个位置中选择 \( k \) 个位置放置物品(或者等价地,选择 \( n - 1 \) 个位置放置隔板)。
选择 \( k \) 个位置放置物品的方法数,就是从 \( k + n - 1 \) 个位置中选择 \( k \) 个位置的组合数,即:
$$ C(k + n - 1, k) $$
或者,选择 \( n - 1 \) 个位置放置隔板的方法数,即:
$$ C(k + n - 1, n - 1) $$
因为组合数 \( C(n, k) \) 等于 \( C(n, n - k) \)(即从 \( n \) 个不同元素中选取 \( k \) 个元素的组合数等于从这 \( n \) 个元素中选取另外 \( n - k \) 个元素的组合数),上面两个公式是等价的。
当你有 \( k \) 个不可区分的物品(比如 \( k \) 个星号 *)要放入 \( n \) 个可区分的盒子中时,直觉上可能会认为每个物品都有 \( n \) 个选择,从而得出 \( n^k \) 的结果。然而,这个直觉仅适用于物品是可区分的情况。在这个问题中,由于物品是不可区分的,我们不能简单地将选择数相乘。
为什么 \( n^k \) 不正确?因为 \( n^k \) 计算了所有可能的排列,假设每个物品是可区分的。例如,如果你有两个可区分的球(一个红色,一个蓝色),它们可以放入两个不同的盒子中,那么确实有 \( 2^2 = 4 \) 种放置方式(红球在盒子1,蓝球在盒子2;红球在盒子2,蓝球在盒子1;两球都在盒子1;两球都在盒子2)。
但是,如果两个球是不可区分的,那么“红球在盒子1,蓝球在盒子2”和“红球在盒子2,蓝球在盒子1”这两种情况实际上是相同的,因为球之间没有区别。所以实际上只有3种不同的放置方式。
如果盒子不可以为空,每个盒子至少有一个物品。这个问题稍微复杂一点,因为我们首先需要给每个盒子分配一个物品,确保没有盒子是空的,然后再将剩余的物品以可重复组合的方式放入盒子中。
首先,我们将 \( k \) 个物品中的 \( n \) 个分配给每个盒子一个,这样每个盒子就都不为空了。剩下 \( k - n \) 个物品需要放入 \( n \) 个盒子中,这时盒子可以为空。
使用隔板法,我们需要从 \( (k - n) + (n - 1) \) 个位置中选择 \( n - 1 \) 个位置放置隔板。组合数为:
$$
C((k - n) + n - 1, n - 1) = C(k - 1, n - 1)
$$
或者,选择 \( k - n \) 个位置放置剩余的星号,组合数为:
$$
C(k - 1, k - n)
$$
同样,这两个公式也是等价的。
设想有$n$个可供选择的对象(比如数字1到$n$),我们要从中选择$k$个,使得任意两个被选择的对象不相邻。
推导步骤:
- 我们考虑$k$个对象在最紧凑的情况下会占据多少空间。每个选中的对象后面(除了最后一个)都需要至少一个未选中的对象来保证不相邻,因此最小长度为$k + (k - 1) = 2k - 1$。
- 如果$n > 2k - 1$,则我们有额外的$n - (2k - 1)$个空间可以分配。这些额外的空间可以放在$k$个对象之间或两端。
- 我们需要将这$n - (2k - 1)$个额外空间分配到$k + 1$个槽中($k - 1$个在对象之间的槽和两端的2个槽)。
- 将$n - (2k - 1)$个相同的空间分配到$k + 1$个不同的槽中,是一个典型的“划分”问题,可以用组合公式$C(n - k + 1, k)$来计算。
不相邻的组合数可以用以下组合公式表示:
$$
C(n - k + 1, k)
$$
Wallis公式是无穷乘积的形式,用于计算圆周率 $\pi$ 的一个近似值。这个公式是由约翰·沃利斯(John Wallis)在1655年发现的,是早期分析学和无穷乘积理论的重要成果之一。Wallis公式表达了半圆的面积(即 $\pi/2$)和无穷乘积之间的关系。
Wallis公式如下:
$$
\frac{\pi}{2} = \prod_{n=1}^{\infty} \frac{(2n)(2n)}{(2n-1)(2n+1)} = \frac{2}{1} \cdot \frac{2}{3} \cdot \frac{4}{3} \cdot \frac{4}{5} \cdot \frac{6}{5} \cdot \frac{6}{7} \cdot \frac{8}{7} \cdot \frac{8}{9} \cdots
$$
这个公式可以通过考虑正弦函数的无穷乘积展开或者通过积分方法来证明。
Wallis公式的一个有趣特点是,它交替地使用了偶数和奇数,而且每个偶数都会出现两次:一次在分子上,一次在分母上。这种交错的模式使得无穷乘积逐渐逼近 $\pi/2$ 的真实值,但收敛速度相对较慢。因此,虽然Wallis公式在数学理论上很重要,但在实际计算 $\pi$ 的高精度值时,通常会使用更快速的算法。
Stirling公式是一个用于近似阶乘(n!)的非常有用的数学表达式,尤其是当 \( n \) 很大时。这个公式是由数学家詹姆斯·斯特林提出的,通常写作:
$$
n! \sim \sqrt{2 \pi n} \left( \frac{n}{e} \right)^n
$$
其中 \( e \) 是自然对数的底数,约等于 2.71828。这个公式表明,当 \( n \) 趋于无穷大时,\( n! \) 与其右侧的表达式的比值趋于 1。
证明Stirling公式的一个方法是使用积分测试和对数函数的性质。这里提供一个简化的版本,它涉及到对数函数的积分和极限。
证明的大致步骤如下:
- **对数函数的应用**:
由于阶乘涉及到大量连乘项,我们首先对 \( n! \) 取自然对数:
$$
\ln(n!) = \ln(1) + \ln(2) + \ln(3) + \cdots + \ln(n)
$$
- **积分近似**:
使用积分来近似这个和(这是一个黎曼和的近似),我们有:
$$
\int_1^n \ln(x) \, dx \leq \ln(n!) \leq \int_1^{n+1} \ln(x) \, dx
$$
这个积分可以精确计算:
$$
\int \ln(x) \, dx = x \ln(x) - x + C
$$
因此:
$$
n \ln(n) - n + 1 \leq \ln(n!) \leq (n+1) \ln(n+1) - (n+1) + 1
$$
- **极限和斯特林公式**:
通过对这些不等式取极限,可以得到:
$$
\lim_{n \to \infty} \frac{\ln(n!)}{n \ln(n)} = 1
$$
这意味着对于大的 \( n \),\( \ln(n!) \) 可以近似为 \( n \ln(n) - n \)。将这个结果指数化,我们得到:
$$
n! \sim e^{n \ln(n) - n}
$$
这是斯特林公式的对数形式。
二、递推关系与母函数
递推关系的一般形式可以是:
$$
a_n = f(a_{n-1}, a_{n-2}, \ldots, a_{n-k})
$$
其中 \( a_n \) 是序列中的第 \( n \) 项,\( f \) 是一个给定的函数,它以序列的前 \( k \) 项为参数。
(1)**线性同质递推关系**:
这种递推关系的形式是:
$$
a_n = c_1 a_{n-1} + c_2 a_{n-2} + \ldots + c_k a_{n-k}
$$
其中 \( c_1, c_2, \ldots, c_k \) 是常数。如果所有的 \( c \) 值都为零,那么递推关系是同质的。
(2)**线性非同质递推关系**:
这种递推关系在同质的基础上加上了一个非零的函数 \( h(n) \):
$$
a_n = c_1 a_{n-1} + c_2 a_{n-2} + \ldots + c_k a_{n-k} + h(n)
$$
(3)**一阶递推关系**:
这种递推关系只涉及序列的直接前一项:
$$
a_n = f(a_{n-1})
$$
母函数(Generating Function),它通过将序列的项与某个变量的幂关联起来,转化为幂级数的形式,从而能够利用解析函数的方法来研究序列的性质。
(1)**普通母函数(OGF)**:对于序列 \( \{a_n\} \),其普通母函数定义为
$$
A(x) = \sum_{n=0}^{\infty} a_n x^n
$$
其中,\( x \) 是一个形式变量,\( a_n \) 是序列的第 \( n \) 项。
(2)**指数母函数(EGF)**:对于序列 \( \{a_n\} \),其指数母函数定义为
$$
A(x) = \sum_{n=0}^{\infty} a_n \frac{x^n}{n!}
$$
同样,\( x \) 是一个形式变量,而 \( a_n \) 是序列的第 \( n \) 项。
母函数的威力在于它们提供了一种统一的方法来处理序列和组合问题,并且可以与微积分和代数的其他工具相结合,从而解决更复杂的问题。
斐波那契数列(Fibonacci sequence)是数学上一个著名的序列,以意大利数学家斐波那契(Leonardo of Pisa,又名Fibonacci)的名字命名。斐波那契数列的每一项都是前两项之和,其定义如下:
$$
F_0 = 0, \quad F_1 = 1
$$
并且对于所有的 $n \geq 2$,
$$
F_n = F_{n-1} + F_{n-2}
$$
斐波那契数列的前几项如下:
$$
0, 1, 1, 2, 3, 5, 8, 13, 21, 34, \ldots
$$
(1)**普通母函数**:
斐波那契数列的普通母函数可以推导如下。设斐波那契数列的普通母函数为 $F(x)$:
$$
F(x) = F_0 + F_1x + F_2x^2 + F_3x^3 + \cdots = \sum_{n=0}^{\infty} F_nx^n
$$
利用斐波那契数列的定义,我们可以构造出以下的等式:
$$
F(x) - xF(x) - x^2F(x) = F_0 + (F_1 - F_0)x + \sum_{n=2}^{\infty} (F_n - F_{n-1} - F_{n-2})x^n
$$
由于 $F_n = F_{n-1} + F_{n-2}$,所以从 $n=2$ 开始的所有项都会相互抵消,留下:
$$
F(x) - xF(x) - x^2F(x) = F_0 + (F_1 - F_0)x = x
$$
解这个线性方程,我们得到:
$$
F(x) = \frac{x}{1 - x - x^2}
$$
这就是斐波那契数列的普通母函数。通过这个母函数,我们可以使用解析方法来找到斐波那契数列项的封闭形式,这通常涉及到使用部分分式分解和复杂的数学分析。
(2)**封闭形式**:
斐波那契数列的封闭形式(也称为Binet公式)是:
$$
F_n = \frac{\phi^n - (1-\phi)^n}{\sqrt{5}}
$$
其中 $\phi = \frac{1 + \sqrt{5}}{2}$ 是黄金分割比,约等于1.6180339887...。这个公式可以直接计算出斐波那契数列的任意项,而不需要递归计算前两项。
(1)**线性性**:如果有两个序列的母函数分别是 $A(x)$ 和 $B(x)$,那么这两个序列的线性组合 $c_1a_n + c_2b_n$ 的母函数就是 $c_1A(x) + c_2B(x)$,其中 $c_1$ 和 $c_2$ 是常数。
(2)**位移性质**:序列 $\{a_n\}$ 的母函数是 $A(x)$,那么序列 $\{a_{n+k}\}$ 的母函数是 $x^{-k}A(x)$,减去了 $A(x)$ 中的前 $k$ 项。
(3)**导数性质**:序列 $\{na_n\}$ 的普通母函数是 $A'(x)$,即原序列 $\{a_n\}$ 普通母函数的导数。对于指数母函数,序列 $\{na_n\}$ 的母函数是 $x \cdot A'(x)$。
(4)**卷积性质**:两个序列的卷积是通过点对点乘法和后续求和得到的。如果 $c_n = \sum_{k=0}^{n} a_k b_{n-k}$,那么序列 $\{c_n\}$ 的母函数是 $C(x) = A(x)B(x)$。
(5)**组合性质**:如果序列 $\{a_n\}$ 的母函数是 $A(x)$,那么序列 $\{a_n^n\}$ 的母函数是 $A(x^n)$。
(6)**逆元性质**:如果序列 $\{a_n\}$ 的母函数是 $A(x)$ 并且 $a_0 \neq 0$,那么它的逆序列 $\{b_n\}$(使得其母函数 $B(x)$ 满足 $A(x)B(x) = 1$)存在,并且可以通过幂级数的除法找到。
(7)**组合解释**:母函数可以用来计数。例如,序列 $\{a_n\}$ 可能代表了某种结构的计数,而母函数 $A(x)$ 就是这些结构的“计数器”。
(8)**泰勒展开**:母函数可以被看作是其系数序列的泰勒展开,这意味着序列的项可以通过母函数的导数在某点的值得到。
(9)**渐近分析**:母函数可以用来研究序列的渐近行为。通过分析母函数在某些特定点的行为,可以得到序列项随着 $n$ 增大的渐近估计。
(10)**函数方程**:序列的递推关系可以转换为母函数的函数方程。解这些方程有时可以直接得到母函数的封闭形式,或者至少可以得到其性质的信息。
线性常系数齐次递推关系是一类特定的递推关系,其特点是下一个项只与前面有限个项的线性组合有关,且系数不随项的位置变化。具体来说,一个$k$阶线性常系数齐次递推关系可以表示为:
$$
a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k}
$$
其中,$c_1, c_2, \ldots, c_k$ 是常数,且对所有的 $n \geq k$ 都成立。齐次意味着没有非零自由项(或称非齐次项)。
为了解这样的递推关系,通常的方法是构造特征方程(也称为特征多项式)。特征方程是根据递推关系构造的一个$k$阶多项式方程,形式如下:
$$
r^k - c_1r^{k-1} - c_2r^{k-2} - \cdots - c_k = 0
$$
通过解这个方程,可以找到$k$个根$r_1, r_2, \ldots, r_k$(其中一些根可能是重根)。然后,根据这些根,可以写出递推关系的通解。具体的通解形式取决于根的情况:
- **所有根都是不同的:** 如果所有的特征根$r_i$都是唯一的,则解可以表示为:
$$
a_n = A_1r_1^n + A_2r_2^n + \cdots + A_kr_k^n
$$
其中,$A_1, A_2, \ldots, A_k$ 是基于初始条件确定的常数。
- **有重根存在:
- **有复数根
线性常系数非齐次递推关系是另一类递推关系,与齐次递推关系相似,但包含一个非零的自由项。这类递推关系的一般形式是:
$$
a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k} + f(n)
$$
其中,$c_1, c_2, \ldots, c_k$ 是常数,$f(n)$ 是一个关于$n$的已知函数,它是非齐次项,也称为驱动项或源项。
要解决这类递推关系,通常分三步进行:
(1)**找到齐次部分的通解**:忽略非齐次项$f(n)$,只考虑对应的齐次递推关系,即:
$$
a_n = c_1a_{n-1} + c_2a_{n-2} + \cdots + c_ka_{n-k}
$$
解这个齐次递推关系,就像我之前描述的那样,通过构造特征方程并找到其根来得到通解。
(2)**找到特解**:找到一个特定的解$A_n$,它满足原始的非齐次递推关系。这个特解取决于非齐次项$f(n)$的形式。有几种方法可以找到特解:
- **待定系数法**:如果$f(n)$是多项式、指数函数、正弦或余弦函数的线性组合,我们可以假设一个特解的形式,并将其代入递推关系中解出系数。
- **生成函数法**:使用母函数技术,我们可以将递推关系转换为生成函数的函数方程,然后解这个方程来找到特解。
- **变系数法**:当待定系数法不适用时,可以使用变系数法,它涉及到解一个与原递推关系相关的线性系统。
(3)
**合并通解和特解**:最后,非齐次递推关系的通解是齐次递推关系的通解与特解的和:
$$
a_n = \text{齐次解} + A_n
$$
其中齐次解是齐次递推关系的通解,$A_n$是特解。最终的解会利用初始条件来确定任何剩余的常数。
整数的拆分是数论和组合数学中的一个重要问题,它研究的是将一个正整数写为一些特定整数的和的方式。这些整数的和被称为该正整数的一个“拆分”。根据拆分的规则不同,整数拆分可以有多种不同的形式,比如:
- **不限制加数的整数拆分**:这是最基本的整数拆分,不对加数的大小或者使用次数做任何限制。例如,整数4的拆分有五种不同的方式:4, 3+1, 2+2, 2+1+1, 1+1+1+1。
- **限制加数的整数拆分**:可能会对加数的大小、使用次数或者其他属性做出限制。例如,我们可能只对拆分成不同加数的情况感兴趣,或者只允许使用奇数加数。
- **有序整数拆分(整数划分)**:在这类拆分中,加数的顺序被考虑在内。比如,对于数字4,有序拆分包括:4, 3+1, 1+3, 2+2, 2+1+1, 1+2+1, 1+1+2, 1+1+1+1。
解决整数拆分问题通常涉及到生成函数和递推关系。
Ferrers图(又称费雷斯图或点阵图)是整数分拆的一种图形表示方法。它通过排列点阵来可视化整数的分拆。Ferrers图的每一行代表分拆中的一个加数,并且行中的点数等于该加数的大小。通常,行按照加数的大小以非增序排列,即最大的加数在顶部,最小的在底部。
例如,整数6的一个分拆是4+1+1,其对应的Ferrers图为:
● ● ● ●
●
●
每个点代表分拆中的一个单位,每行的点数代表一个加数,上面的图中最长的一行有4个点,表示加数4,接下来是两行,每行一个点,表示加数1。
Ferrers图不仅可以表示分拆,还可以用来证明分拆的一些性质。例如,Ferrers图可以用来证明整数分拆的共轭性质,即通过将Ferrers图沿着其对角线翻转,可以从一个分拆得到另一个分拆。共轭分拆在加数的数量与大小之间建立了对应关系。
以整数5的分拆为例,我们有以下Ferrers图:
原分拆 3+2 对应的Ferrers图:
● ● ●
● ●
翻转后得到共轭分拆 2+2+1 对应的Ferrers图:
● ●
● ●
●
整数分拆问题的一个重要方面是估计整数$n$的分拆数$p(n)$,特别是当$n$很大时。精确计算$p(n)$是非常困难的,因为它随着$n$的增长而迅速增加。然而,数学家们已经开发出了一些用于估计$p(n)$的公式和方法。
最著名的估计公式之一是由哈代和拉马努金给出的渐近公式,后来由拉杜加改进。哈代-拉马努金-拉杜加公式(Hardy-Ramanujan-Rademacher公式)提供了一个非常精确的$p(n)$的渐近表达式:
$$
p(n) \sim \frac{1}{4n\sqrt{3}} \exp\left(\pi \sqrt{\frac{2n}{3}}\right) \quad \text{当} \quad n \to \infty
$$
这个公式表明$p(n)$的增长速度大约是指数级的,具体来说,是与$\exp\left(\pi \sqrt{\frac{2n}{3}}\right)$成正比。
更精确的表达式涉及到无穷级数和Bessel函数,但上面的简化公式在实际应用中已经足够给出非常接近的估计值。
广义二项式定理是传统二项式定理的一个扩展,它适用于任何实数指数,而不仅仅是非负整数。这个定理表明,对于任何实数$\alpha$和任何复数$x$和$y$,只要$|x| > |y|$,就有:
$$(x + y)^\alpha = \sum_{k=0}^{\infty} \binom{\alpha}{k} x^{\alpha-k} y^k$$
其中,二项式系数(binomial coefficient)$\binom{\alpha}{k}$是用$\alpha$和$k$表示的,并且定义为:
$$\binom{\alpha}{k} = \frac{\alpha(\alpha-1)(\alpha-2) \cdots (\alpha-k+1)}{k!}$$
对于$k=0$,我们定义$\binom{\alpha}{0} = 1$。
当$k$大于0时,二项式系数可以使用Gamma函数($\Gamma(z)$)来进一步泛化,因为Gamma函数是阶乘的推广:
$$\binom{\alpha}{k} = \frac{\Gamma(\alpha+1)}{\Gamma(k+1)\Gamma(\alpha-k+1)}$$
这里,$\Gamma(n) = (n-1)!$ 对于所有正整数$n$成立。
广义二项式定理的一个特殊情况是当$x=1$时,它简化为:
$$(1 + y)^\alpha = \sum_{k=0}^{\infty} \binom{\alpha}{k} y^k$$
这个级数在$|y|<1$时收敛。
(1)第一类斯特林数
第一类斯特林数(Stirling numbers of the first kind),记为 $s(n, k)$ 或 $\begin{bmatrix} n \\ k \end{bmatrix}$,用来计数将 $n$ 个对象排列成 $k$ 个非空循环排列(也称为圆排列)的方法数。这些数学对象在排列、代数以及组合数学中都有重要的应用。
第一类斯特林数可以递归地定义为:
- $s(n, n) = 1$ 对于所有的 $n \geq 0$。
- $s(n, 0) = 0$ 对于所有的 $n \geq 1$。
- $s(n, k) = s(n-1, k-1) - (n-1) \cdot s(n-1, k)$ 对于所有的 $n > k \geq 1$。
第一类斯特林数的递归关系 $s(n, k) = s(n-1, k-1) - (n-1) \cdot s(n-1, k)$ 可以通过组合数学中的排列和循环排列的概念来理解。
- **新增单独循环**:$s(n-1, k-1)$ 表示将 $n-1$ 个元素排列成 $k-1$ 个循环的方法数。当我们添加第 $n$ 个元素时,我们可以将这个新元素作为一个新的单独循环添加到现有的循环排列中。这样,我们就从 $k-1$ 个循环转变为 $k$ 个循环。因为新元素单独成为一个循环,所以不会影响原来 $n-1$ 个元素的循环排列方式,所以这一部分直接贡献了 $s(n-1, k-1)$ 种方法。
- **插入现有循环**:$(n-1) \cdot s(n-1, k)$ 表示将 $n-1$ 个元素排列成 $k$ 个循环的方法数,然后将第 $n$ 个元素插入到这些现有循环的任意位置。因为每个循环排列中有 $n-1$ 个可能的插入点(每个现有元素前面都是一个可能的插入点),所以对于每一种现有的排列,都有 $n-1$ 种方法来插入新元素。但这样的插入会破坏原有的循环结构,因此我们需要从总数中减去这些情况。
**符号问题**:第一类斯特林数可以是负数,这是因为它们也可以被视为排列的某种“符号版本”。具体来说,$s(n, k)$ 的符号由 $(-1)^{n-k}$ 决定。
**与排列多项式的关系**:第一类斯特林数出现在排列多项式的展开中。排列多项式 $x(x-1)(x-2)...(x-n+1)$ 的展开中,$x^k$ 的系数就是 $s(n, k)$,乘以 $(-1)^{n-k}$。
**三角形排列**:与帕斯卡三角形类似,第一类斯特林数也可以通过一个三角形的排列来逐行构建,每个数都是它上一行的左邻居加上它上一行的右邻居乘以一个因子。
(2)第二类斯特林数
第二类斯特林数(Stirling numbers of the second kind),记为 $S(n, k)$ 或 $\left\{{n \atop k}\right\}$,用来计数将 $n$ 个不同对象划分为 $k$ 个非空不可区分(即顺序不重要)的集合的方法数。第二类斯特林数在组合数学中有广泛的应用,尤其是在涉及集合划分和多项式幂次的计数问题中。
第二类斯特林数可以递归地定义为:
- $S(n, n) = 1$ 对于所有的 $n \geq 0$。
- $S(n, 0) = 0$ 对于所有的 $n \geq 1$。
- $S(n, k) = k \cdot S(n-1, k) + S(n-1, k-1)$ 对于所有的 $n > k \geq 1$。
卡塔兰数(Catalan numbers)是组合数学中一个重要的数列,用于计数许多不同类型的组合结构。它们由数学家Eugène Charles Catalan命名。第 $n$ 个卡塔兰数通常表示为 $C_n$,可以通过以下公式计算:
$$
C_n = \frac{1}{n+1}\binom{2n}{n} = \frac{(2n)!}{(n+1)!n!}
$$
卡塔兰数的前几项是:1, 1, 2, 5, 14, 42, 132, ...
卡塔兰数序列也满足以下递归关系:
$$
C_0 = 1 \quad \text{和} \quad C_{n+1} = \frac{2(2n+1)}{n+2}C_n
$$
或者
$$
C_n = \sum_{i=0}^{n-1} C_i C_{n-1-i}, \quad \text{对于} \quad n \geq 1
$$
卡塔兰数在数学中的应用非常广泛,它们出现在各种计数问题中,包括:
- **路径问题**:$C_n$ 计数在一个 $n \times n$ 的格点方阵中,从左下角到右上角只向上或向右移动并且不越过对角线的不同路径数。
- **二叉树**:$C_n$ 计数有 $n$ 个节点的不同形状的二叉树的数量。
- **多边形三角剖分**:$C_n$ 计数将一个凸多边形分割成三角形的不同方法数(多边形有 $n+2$ 个顶点)。
- **栈排序**:$C_n$ 计数长度为 $n$ 的序列通过栈排序后能够保持原有顺序的不同排列数。
三、容斥原理与鸽巢原理
容斥原理(Inclusion-Exclusion Principle)是组合数学中的一个重要原理,用于计算多个集合的并集的元素数量。它通过对集合的交集进行适当的加减修正,来纠正简单并集计数中的重复计数问题。
假设我们有 $n$ 个集合 $A_1, A_2, ..., A_n$,容斥原理提供了计算它们并集的元素数量 $|A_1 \cup A_2 \cup ... \cup A_n|$ 的方法。
对于两个集合 $A$ 和 $B$,容斥原理表达式为:
$$
|A \cup B| = |A| + |B| - |A \cap B|
$$
这个公式计算了 $A$ 和 $B$ 的并集的大小,首先加上 $A$ 的大小和 $B$ 的大小,然后减去 $A$ 和 $B$ 共有的部分,以消除重复计数。
对于三个集合 $A$, $B$ 和 $C$,容斥原理变得稍微复杂一些:
$$
|A \cup B \cup C| = |A| + |B| + |C| - |A \cap B| - |A \cap C| - |B \cap C| + |A \cap B \cap C|
$$
这里我们首先加上每个单独集合的大小,然后减去所有可能的两个集合交集的大小,最后加上三个集合共有部分的大小,以确保正确计数。
广义容斥原理的数学表达式是:
$$
|\bigcup_{i=1}^{n} A_i| = \sum_{k=1}^{n} (-1)^{k+1} \left( \sum_{1 \leq i_1 < i_2 < \ldots < i_k \leq n} |\bigcap_{j=1}^{k} A_{i_j}| \right)
$$
在这个公式中:
- 外层求和遍历从 $1$ 到 $n$ 的所有整数 $k$,对应于交集中的集合数。
- 内层求和遍历所有大小为 $k$ 的集合的索引 $i_1, i_2, \ldots, i_k$ 的组合。
- $|\bigcap_{j=1}^{k} A_{i_j}|$ 表示所有索引为 $i_1, i_2, \ldots, i_k$ 的集合的交集的大小。
- $(-1)^{k+1}$ 是一个交替的符号,它随着交集中集合数量的奇偶性改变。
第二类斯特林数可以通过下面的递归关系来定义:
$$
S(n, k) = k \cdot S(n-1, k) + S(n-1, k-1)
$$
第二类斯特林数的显式表达式可以通过包含求和的公式给出:
$$
S(n, k) = \frac{1}{k!} \sum_{i=0}^{k} (-1)^{k-i} {k \choose i} i^n
$$
在这个公式中,${k \choose i}$ 是二项式系数,表示从 $k$ 个物体中选择 $i$ 个物体的方法数。这个公式可以直接计算任意 $n$ 和 $k$ 的第二类斯特林数,不过当 $n$ 和 $k$ 较大时,计算可能会变得比较复杂。
欧拉函数(Euler's totient function),通常表示为 $\varphi(n)$ 或 $\phi(n)$,是数论中的一个重要函数。它定义为小于或等于 $n$ 的正整数中与 $n$ 互质的数的个数。换句话说,对于给定的正整数 $n$,欧拉函数 $\varphi(n)$ 计数的是在 $1$ 到 $n$ 的范围内,所有与 $n$ 共享没有公因数(除了 $1$)的正整数的数量。
欧拉函数的值可以通过 $n$ 的素数分解来计算。如果 $n$ 的素数分解为
$$
n = p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_r^{k_r}
$$
其中 $p_1, p_2, \ldots, p_r$ 是不同的素数,而 $k_1, k_2, \ldots, k_r$ 是它们对应的指数,则欧拉函数可以用以下乘积形式计算:
$$
\varphi(n) = n \left(1 - \frac{1}{p_1}\right) \left(1 - \frac{1}{p_2}\right) \ldots \left(1 - \frac{1}{p_r}\right)
$$
(1)几个重要的性质
- 如果 $n$ 是一个素数,那么 $\varphi(n) = n - 1$,因为所有小于 $n$ 的正整数都与 $n$ 互质。
- 如果 $n$ 可以表示为两个互质正整数的乘积,即 $n = a \cdot b$,那么 $\varphi(n) = \varphi(a) \cdot \varphi(b)$。
- 对于任何正整数 $n$ 和 $m$,如果 $m$ 是 $n$ 的倍数,则 $\varphi(m)$ 是 $\varphi(n)$ 的倍数。
- 欧拉函数是乘性函数,但不是完全乘性的。也就是说,如果 $a$ 和 $b$ 是互质的,则 $\varphi(ab) = \varphi(a)\varphi(b)$,但如果 $a$ 和 $b$ 不是互质的,这个关系可能不成立。
(2)推导过程
假设 $n$ 的素数分解为
$$
n = p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_r^{k_r}
$$
其中 $p_1, p_2, \ldots, p_r$ 是不同的素数,而 $k_1, k_2, \ldots, k_r$ 是它们对应的指数。我们可以使用以下步骤来推导 $\varphi(n)$ 的公式:
- **计算单个素数幂的欧拉函数**:首先,我们知道对于每个素数幂 $p_i^{k_i}$,与其互质的数的个数是 $p_i^{k_i} - p_i^{k_i - 1}$(每数p个数即有一个倍数)。这是因为从 $1$ 到 $p_i^{k_i}$ 的数中,除了 $p_i$ 的倍数外,其他的都与 $p_i^{k_i}$ 互质。
-
**使用乘性质**:欧拉函数是一个乘性函数,这意味着如果两个正整数 $a$ 和 $b$ 互质(即 $\gcd(a, b) = 1$),那么 $\varphi(ab) = \varphi(a)\varphi(b)$。由于 $n$ 的素数分解中的每个 $p_i^{k_i}$ 都是互质的,我们可以将 $\varphi(n)$ 写成这些素数幂的欧拉函数的乘积:
$$
\varphi(n) = \varphi(p_1^{k_1}) \cdot \varphi(p_2^{k_2}) \cdot \ldots \cdot \varphi(p_r^{k_r})
$$ -
**代入单个素数幂的欧拉函数值**:将每个 $\varphi(p_i^{k_i})$ 的值代入上面的乘积中:
$$
\varphi(n) = (p_1^{k_1} - p_1^{k_1 - 1}) \cdot (p_2^{k_2} - p_2^{k_2 - 1}) \cdot \ldots \cdot (p_r^{k_r} - p_r^{k_r - 1})
$$ -
**简化公式**:将每个因子写成 $p_i^{k_i} \left(1 - \frac{1}{p_i}\right)$ 的形式:
$$
\varphi(n) = p_1^{k_1} \left(1 - \frac{1}{p_1}\right) \cdot p_2^{k_2} \left(1 - \frac{1}{p_2}\right) \cdot \ldots \cdot p_r^{k_r} \left(1 - \frac{1}{p_r}\right)
$$ -
**得到最终公式**:由于 $n = p_1^{k_1} \cdot p_2^{k_2} \cdot \ldots \cdot p_r^{k_r}$,我们可以将上面的表达式写成:
$$
\varphi(n) = n \left(1 - \frac{1}{p_1}\right) \left(1 - \frac{1}{p_2}\right) \ldots \left(1 - \frac{1}{p_r}\right)
$$
鸽巢原理,也称为抽屉原理或狄利克雷抽屉原理(Dirichlet's box principle),是组合数学中的一个基本原理。其基本形式可以非正式地叙述如下:
如果有 $n+1$ 只鸽子要放进 $n$ 个鸽巢里,至少会有一个鸽巢里有不少于两只鸽子。
换句话说,如果要将一个以上的物体分配到一定数量的容器中,至少有一个容器将包含多于一个的物体。
鸽巢原理的一般形式是:
如果有 $n$ 个容器和 $m$ 个物体,且 $m > n$,则至少有一个容器包含不少于 $\left\lceil \frac{m}{n} \right\rceil$ 个物体,其中 $\left\lceil x \right\rceil$ 表示 $x$ 的上取整。
如果有 $m$ 个物体和 $n$ 个容器,并且 $m > kn$(其中 $k$ 是一个正整数),那么至少有一个容器包含超过 $k$ 个物体。
如果 $m \leq kn$,那么可以将物体分配到容器中,使每个容器中不多于 $k$ 个物体。
Ramsey数是组合数学中的一个概念,它是图论的一个分支。Ramsey数可以简单地理解为:在完全随机的结构中寻找有序结构的问题。具体来说,它回答了这样一个问题:在一个图中,至少需要多少个顶点,才能确保无论如何对边进行红色或蓝色着色,都必然会出现一个完全由红色边连接的子图或一个完全由蓝色边连接的子图。
最经典的Ramsey数是 $R(m, n)$,它代表了最小的数 $r$,使得所有的两色(通常用红色和蓝色表示)边着色的完全图 $K_r$ 中,必然含有一个红色的 $K_m$ 或一个蓝色的 $K_n$。这里,$K_r$ 表示有 $r$ 个顶点的完全图,$K_m$ 和 $K_n$ 分别表示有 $m$ 和 $n$ 个顶点的完全子图。
例如,$R(3, 3)$ 是最小的数,使得在任何六边形(即$K_6$)中,无论如何对边进行红蓝着色,都必然会有一个红色的三角形或一个蓝色的三角形。$R(3, 3)$ 的值是6。
Ramsey数的问题是非常难解的,因为它们涉及到的组合可能性非常庞大,即使对于相对较小的 $m$ 和 $n$,计算 $R(m, n)$ 也是非常困难的。目前已知的Ramsey数非常少,只有 $R(m, n)$ 在 $m$ 或 $n$ 较小的时候已知。
四、Burnside引理Polya原理
一个群由以下两部分组成:
- 一个集合 $G$,其元素可以是任意类型的数学对象。
- 一个二元运算 $\cdot$,它将任意两个元素 $a$ 和 $b$ 映射到一个元素 $c$,即 $a \cdot b = c$,其中 $c$ 也是集合 $G$ 中的元素。
这个结构必须满足以下四个群公理:
- **封闭性**:对于所有 $G$ 中的元素 $a$ 和 $b$,运算结果 $a \cdot b$ 也在 $G$ 中。
- **结合律**:对于所有 $G$ 中的元素 $a$、$b$ 和 $c$,有 $(a \cdot b) \cdot c = a \cdot (b \cdot c)$。
- **单位元存在性**:在 $G$ 中存在一个元素 $e$,称为单位元(或幺元),使得对于所有 $G$ 中的元素 $a$,有 $e \cdot a = a \cdot e = a$。
- **逆元存在性**:对于 $G$ 中的每个元素 $a$,存在一个对应的元素 $b$ 在 $G$ 中,称为 $a$ 的逆元,使得 $a \cdot b = b \cdot a = e$,其中 $e$ 是单位元。
如果群的二元运算还满足交换律,即对于所有 $G$ 中的元素 $a$ 和 $b$,都有 $a \cdot b = b \cdot a$,那么这个群被称为交换群或阿贝尔群(Abelian group)。
(1)**单位元的唯一性**:在任何群中,单位元是唯一的。这意味着不能有两个不同的元素都表现为单位元。
(2)**逆元的唯一性**:在任何群中,每个元素的逆元也是唯一的。对于群中的任意元素 $a$,存在唯一的元素 $b$ 使得 $a \cdot b = b \cdot a = e$,其中 $e$ 是单位元。
(3)**解方程的能力**:对于群中的任意元素 $a$ 和 $b$,方程 $a \cdot x = b$ 和 $y \cdot a = b$ 在群中都有唯一解。这意味着我们可以“除以”群的元素。
(4)**运算的可逆性**:由于每个元素都有逆元,群中的每个操作都是可逆的。如果 $a \cdot b = c$,那么 $c \cdot b^{-1} = a$ 和 $a^{-1} \cdot c = b$,其中 $b^{-1}$ 和 $a^{-1}$ 分别是 $b$ 和 $a$ 的逆元。
(5)**左右消去律**:如果 $a \cdot b = a \cdot c$,则 $b = c$;如果 $b \cdot a = c \cdot a$,则 $b = c$。这是因为可以通过乘以逆元来“消去”等式一侧的元素。
(6)**幂的性质**:对于群中的任意元素 $a$ 和整数 $n$,$a$ 的幂 $a^n$ 定义为 $a$ 与自身相乘 $n$ 次。群的结合律保证了幂的运算是良定义的。
(7)**子群的概念**:群的任何非空子集,如果在群的运算下封闭并且自身也形成一个群,则称为原群的子群。
(8)**同态和同构**:如果两个群之间存在一个运算保持的映射(即同态),那么这两个群在结构上是相似的。如果这个映射是双射,那么它们是同构的,即它们在结构上是相同的。
(9)**拉格朗日定理**:在有限群中,任何子群的阶(即元素的个数)都是整个群阶的因子。
(10)**正规子群和商群**:一个子群如果对于群中所有元素都满足共轭封闭性,那么它是一个正规子群。给定一个正规子群,可以构造出一个所谓的商群,它的元素是原群元素关于正规子群的等价类。
(1)置换群的定义
置换是指在一个集合上的双射函数,即一个将集合中的元素重新排列的函数。
- **封闭性**:任意两个置换的复合(即先进行一个置换,再进行另一个置换)仍然是一个置换。
- **结合律**:置换的复合满足结合律,即对于任意三个置换 $\sigma$、$\tau$ 和 $\phi$,有 $(\sigma \circ \tau) \circ \phi = \sigma \circ (\tau \circ \phi)$。
- **单位元**:存在一个单位置换,它对任何元素都不进行置换,即对于任何元素 $x$,都有 $e(x) = x$。单位置换作为单位元,满足对于任何置换 $\sigma$,都有 $e \circ \sigma = \sigma \circ e = \sigma$。
- **逆元**:对于每个置换 $\sigma$,存在一个逆置换 $\sigma^{-1}$,使得 $\sigma \circ \sigma^{-1} = \sigma^{-1} \circ \sigma = e$。
(2)置换群的例子
- **对称群**:对于一个包含 $n$ 个元素的集合,所有可能的置换构成的群称为对称群,通常表示为 $S_n$。对称群 $S_n$ 的阶(即元素的数量)是 $n!$($n$ 的阶乘),因为一个 $n$ 元素集合可以有 $n!$ 种不同的排列方式。
- *交错群**:在对称群中,那些奇数次对换的复合构成的置换称为奇置换,而偶数次对换的复合构成的置换称为偶置换。所有偶置换的集合构成一个对称群的正规子群,称为交错群,表示为 $A_n$。如果 $n \geq 2$,则交错群 $A_n$ 的阶是 $\frac{n!}{2}$。
(1)循环(Cycle)
循环是指在置换中,一系列的元素按照一定的顺序循环移动的现象。例如,考虑置换 $\sigma$,它作用在集合 $\{1, 2, 3, 4, 5\}$ 上,如果 $\sigma$ 将 1 映射到 3,3 映射到 4,4 映射到 1,并且保持 2 和 5 不变,那么我们可以表示这个置换为两个循环:$(1, 3, 4)(2)(5)$。这里,$(1, 3, 4)$ 是一个长度为 3 的循环,$(2)$ 和 $(5)$ 是长度为 1 的循环,通常省略不写。
在数学表示中,循环 $(a_1, a_2, ..., a_k)$ 表示一个置换,其中 $a_1$ 被置换到 $a_2$ 的位置,$a_2$ 被置换到 $a_3$ 的位置,依此类推,直到 $a_k$ 被置换回 $a_1$ 的位置。循环的长度就是它包含的元素数量。
(2)奇循环与偶循环
- **奇循环**:如果一个循环的长度减去 1 后是奇数,那么这个循环就是奇循环。换句话说,如果循环长度是偶数,那么它是奇循环。
- **偶循环**:如果一个循环的长度减去 1 后是偶数,那么这个循环就是偶循环。换句话说,如果循环长度是奇数,那么它是偶循环。
这种奇偶性的定义是因为一个长度为 $k$ 的循环可以分解成 $k-1$ 个对换。例如,循环 $(1, 2, 3)$ 可以分解为对换的乘积 $(1, 2)(2, 3)$,这里有两个对换,所以它是一个偶循环。
设 $G$ 是一个有限群,作用在集合 $X$ 上。对于 $G$ 中的每个元素 $g$,定义 $X^g$ 是 $X$ 中在 $g$ 作用下保持不变的元素集合(也就是不动点集合)。那么,$X$ 上的不同轨道($G$-轨道,即通过群作用可以相互到达的元素集合)的数量 $N$ 是所有不动点集合大小的平均值:
$$
N = \frac{1}{|G|} \sum_{g \in G} |X^g|
$$
这里,$|G|$ 表示群 $G$ 的阶(即群的元素数量),$|X^g|$ 表示在元素 $g$ 作用下不动点的数量。
假设我们有一个正三角形,我们想要用两种颜色(比如红色和蓝色)来染它的三个顶点,我们想知道有多少种本质不同的染色方式。这里,“本质不同”是指不能通过旋转三角形来得到的染色方式。三角形的旋转可以构成一个群 $G$,包含三个元素:$e$(不旋转),$r$(顺时针旋转120度),$r^2$(顺时针旋转240度)。集合 $X$ 包含所有可能的染色方案。
按照Burnside引理,我们需要计算每个群元素作用下的不动点数量。
- **恒等元素 $e$**:任何染色方案在不旋转的情况下都保持不变,所以这里的不动点就是所有染色方案。如果我们有两种颜色,那么总共有 $2^3 = 8$ 种染色方案。
- **旋转 $r$**:只有在所有顶点都是同一种颜色时,染色方案才是不动点,因为任何两种颜色的组合在旋转后都会改变。所以这里只有2种不动点(全红或全蓝)。
- **旋转 $r^2$**:与旋转 $r$ 相同,也是2种不动点。
现在,我们可以应用Burnside引理来计算本质不同染色方式的数量:
$$
N = \frac{1}{|G|} \sum_{g \in G} |X^g| = \frac{1}{3} (8 + 2 + 2) = \frac{1}{3} \times 12 = 4
$$
所以,有4种本质不同的染色方式。
Pólya定理(也称为Pólya计数定理)是Burnside引理的一个推广,用于更复杂的计数问题,特别是在对象有多种颜色时。这个定理由匈牙利数学家乔治·波利亚(George Pólya)在1937年提出,并且在组合数学中的计数问题中非常有用,尤其是在考虑对象的对称性时。
设 $G$ 是一个有限群,作用在集合 $X$ 上,且 $X$ 中的元素可以用 $k$ 种不同的颜色进行着色。Pólya定理使用了一个称为循环指标或Pólya生成函数的工具来计数在群 $G$ 的作用下不同的着色方案的数量。这个生成函数是由群 $G$ 的元素的循环结构决定的。
循环指标 $Z(G)$ 对于群 $G$ 的每个元素 $g$,基于 $g$ 将 $X$ 分成的循环(在 $g$ 作用下不变的子集)来构建。每个循环可以独立地用 $k$ 种颜色中的任何一种来着色。如果 $g$ 将 $X$ 分成 $c_1$ 个一元循环、$c_2$ 个二元循环,以此类推,那么 $g$ 对应的项就是 $(x_1^{c_1} x_2^{c_2} \ldots)^k$。
Pólya定理的基本形式是:
$$
P(G, k) = \frac{1}{|G|} \sum_{g \in G} k^{c(g)}
$$
这里,$P(G, k)$ 是在群 $G$ 的作用下,使用 $k$ 种颜色的不同着色方案的数量,$c(g)$ 是元素 $g$ 作用下的循环数量。
让我们通过一个简单的例子来理解Pólya定理的应用:假设我们有一个三珠项链,每个珠子可以用两种颜色(比如红色和蓝色)来着色。我们想要计算在旋转对称性下有多少种不同的着色方式。
首先,我们需要确定项链的旋转群。由于项链有三个珠子,群 $G$ 由三个元素组成:$e$(恒等操作,不做任何旋转),$r$(顺时针旋转一个珠子的位置),和 $r^2$(顺时针旋转两个珠子的位置)。注意,$r^3$ 就是恒等操作,所以不需要再次考虑。
对于恒等操作 $e$,它不改变任何珠子的位置,所以有三个一元循环。
对于旋转 $r$,所有三个珠子都在一个循环中。
对于旋转 $r^2$,情况与 $r$ 相同,所有三个珠子都在一个循环中。
现在我们可以应用Pólya定理来计数:
$$
P(G, k) = \frac{1}{|G|} \sum_{g \in G} k^{c(g)}
$$
在这个例子中,$k=2$(两种颜色),$|G|=3$(三种旋转),我们得到:
$$
P(G, 2) = \frac{1}{3} \left( 2^3 + 2^1 + 2^1 \right)
$$
对于恒等操作 $e$,有 $2^3$ 种着色方式,因为每个珠子都可以独立选择颜色。
对于旋转 $r$ 和 $r^2$,由于所有珠子都在同一个循环中,所以只有 $2^1$ 种着色方式,因为一旦选择了一个珠子的颜色,其余珠子的颜色也就确定了。
计算这个表达式,我们得到:
$$
P(G, 2) = \frac{1}{3} (8 + 2 + 2) = \frac{1}{3} \times 12 = 4
$$
因此,存在4种本质不同的着色方式。
五、区组设计
(1)拉丁方 (Latin Square)
一个 $n \times n$ 的拉丁方是一个填充了 $n$ 种不同符号的方阵,每种符号在每一行和每一列中恰好出现一次。拉丁方的一个经典例子是数独,它是一个 $9 \times 9$ 的拉丁方,其中每个 $3 \times 3$ 的子方阵也包含了1到9的所有数字。
#### 例子:
一个 $3 \times 3$ 的拉丁方可以是:
$$
\begin{matrix}
1 & 2 & 3 \\
2 & 3 & 1 \\
3 & 1 & 2 \\
\end{matrix}
$$
在这个例子中,数字1、2和3在每一行和每一列中都恰好出现一次。
(2)正交拉丁方 (Orthogonal Latin Squares)
两个拉丁方是正交的,如果你可以将它们叠加在一起(一个放在另一个上面),使得每一对符号(一个来自于第一个拉丁方,另一个来自于第二个拉丁方)在这个叠加方阵的任何位置都是唯一的。换句话说,如果你有两个拉丁方 $L_1$ 和 $L_2$,当你在位置 $(i, j)$ 放置一个来自 $L_1$ 的符号和一个来自 $L_2$ 的符号时,这种组合在方阵的任何其他位置都不会再次出现。
考虑以下两个 $3 \times 3$ 的拉丁方:
$$
L_1 = \begin{matrix}
1 & 2 & 3 \\
2 & 3 & 1 \\
3 & 1 & 2 \\
\end{matrix}
\quad
L_2 = \begin{matrix}
1 & 3 & 2 \\
3 & 2 & 1 \\
2 & 1 & 3 \\
\end{matrix}
$$
这两个拉丁方是正交的,因为如果你将 $L_2$ 放在 $L_1$ 上面,那么每个位置的数字对 (如 $(1,1)$, $(2,3)$, $(3,2)$ 等) 都是唯一的。
域是一个集合 $F$,在其上定义了两种二元运算:加法(记为 +)和乘法(记为 ·),并满足以下公理:
(1)**加法公理:
- 封闭性:对于所有 $a, b \in F$,有 $a + b \in F$。
- 交换律:$a + b = b + a$。
- 结合律:$(a + b) + c = a + (b + c)$。
- 加法单位元:存在元素 $0 \in F$,使得对于所有 $a \in F$,有 $a + 0 = a$。
- 加法逆元:对于每个 $a \in F$,存在元素 $-a \in F$,使得 $a + (-a) = 0$。
(2) **乘法公理:
- 封闭性:对于所有 $a, b \in F$,有 $a \cdot b \in F$。
- 交换律:$a \cdot b = b \cdot a$。
- 结合律:$(a \cdot b) \cdot c = a \cdot (b \cdot c)$。
- 乘法单位元:存在元素 $1 \in F$($1 \neq 0$),使得对于所有 $a \in F$,有 $a \cdot 1 = a$。
- 乘法逆元:对于每个 $a \in F$($a \neq 0$),存在元素 $a^{-1} \in F$,使得 $a \cdot a^{-1} = 1$。
(3)**分配律:
- 对于所有 $a, b, c \in F$,有 $a \cdot (b + c) = a \cdot b + a \cdot c$。
这些公理确保了域内的运算是良定义的,并且具有我们在实数系统中期望的性质。最熟悉的域的例子可能是有理数集 $\mathbb{Q}$、实数集 $\mathbb{R}$ 和复数集 $\mathbb{C}$,它们都按照以上公理运作。
Galois域(Galois Field),记为 $GF(p^n)$,是包含有限个元素的域,其中 $p$ 是一个素数,而 $n$ 是一个正整数。Galois域是以法国数学家埃瓦里斯特·伽罗瓦(Évariste Galois)命名的,他在域理论和群论方面做出了开创性的贡献。
(1)选择素数和域的大小
首先,选择一个素数 $p$。这个素数是构造域的基础,因为在 Galois 域中的所有数字都是从 $0$ 到 $p-1$ 的整数。然后,确定你想要构造的域的大小,即 $n$,这样域的元素总数就是 $p^n$。
(2)选择不可约多项式
为了定义这些多项式如何相乘,我们需要选择一个不可约多项式,它的次数是 $n$,并且它的系数也是从 $0$ 到 $p-1$ 的整数。不可约多项式就像是规则,告诉我们如何进行乘法运算。
(3)定义加法和乘法
在 Galois 域中,加法很简单,就是对应系数的加法,并在必要时取模 $p$。
乘法稍微复杂一点。我们首先像通常一样进行多项式乘法,然后用选择的不可约多项式来取模,确保结果是一个次数小于 $n$ 的多项式。这样做可以确保所有的运算结果都保持在域内。
(4)举例
让我们以 $GF(2^2)$ 为例,即 $p=2$ 且 $n=2$,这意味着我们的域有 $2^2=4$ 个元素。我们可以选择不可约多项式 $f(x) = x^2 + x + 1$。
这个域的元素可以表示为:
- $0$
- $1$
- $x$
- $x + 1$
这里的 $x$ 是一个多项式的占位符,代表 $x^1$。
加法规则很简单:
- $0 + 0 = 0$
- $1 + 1 = 0$(因为 $2 \equiv 0 \mod 2$)
- $x + x = 0$(因为 $2x \equiv 0 \mod 2$)
- $(x+1) + (x+1) = 0$(因为每个系数都是模 $2$ 加法)
乘法则需要使用不可约多项式 $f(x)$:
- $x \cdot x = x^2 \equiv x + 1 \mod (x^2 + x + 1)$
- $x \cdot (x + 1) = x^2 + x \equiv 1 \mod (x^2 + x + 1)$
- $(x + 1) \cdot (x + 1) = x^2 + 2x + 1 \equiv x \mod (x^2 + x + 1)$
注意,乘法的结果都是通过将多项式除以不可约多项式 $f(x)$ 并取余数得到的。
构造正交拉丁方阵可以通过使用有限域(也称为Galois域)的性质来实现。这种方法特别适用于当阶数 $n$ 是一个素数或者素数的幂时。这是因为在这种情况下,存在一个大小为 $n$ 的有限域 $GF(n)$。
如果 $n$ 是素数,那么 $GF(n)$ 就是整数模 $n$ 的集合 $\{0, 1, 2, \ldots, n-1\}$,加法和乘法都是模 $n$ 的。如果 $n$ 是素数的幂,即 $n = p^k$,那么构造 $GF(n)$ 需要更复杂的数学结构,通常涉及多项式和模一个不可约多项式的运算。
以下是使用有限域构造正交拉丁方阵的一般步骤:
(1)构造有限域
确定阶数 $n$,如果 $n$ 是素数的幂,即 $n = p^k$,则构造有限域 $GF(n)$。对于素数阶,可以直接使用模 $n$ 的整数。对于素数幂阶,需要找到一个不可约多项式,然后在此多项式上进行模运算来构造域元素。
(2)构造拉丁方阵
对于有限域 $GF(n)$ 中的每个元素,构造两个拉丁方阵 $L_1$ 和 $L_2$。通常,第一个拉丁方阵 $L_1$ 可以是一个加法表,而第二个拉丁方阵 $L_2$ 可以是乘法表(或者是有限域中元素与一个固定非零元素的乘积)。
(3)验证正交性
不是所有的有限域都可以用这种方式构造正交拉丁方阵。
一个平衡不完全区组设计 (BIBD) 被定义为一个五元组 $(v, b, r, k, \lambda)$,其中:
- $v$ 是设计中不同元素(被称为“处理”)的总数。
- $b$ 是区组(blocks)的总数。
- $r$ 是每个元素出现在多少个区组中。
- $k$ 是每个区组中的元素数量。
- $\lambda$ 是任意两个不同元素一起出现在区组中的次数。
BIBD 满足以下关系:
$$
vr = bk
$$
这个等式说明了在整个设计中,每个元素出现的总次数($vr$)等于所有区组中包含的元素的总数($bk$)。这是因为每个区组有 $k$ 个元素,共有 $b$ 个这样的区组,所以总共有 $bk$ 个元素的位置。同时,每个元素在 $r$ 个不同的区组中出现,而有 $v$ 个这样的元素,因此总共有 $vr$ 个元素的位置。这个等式确保了设计中的每个元素都有相同的重复次数,即每个元素都平均分布在所有的区组中。
$$
r(k - 1) = \lambda(v - 1)
$$
这个等式关注的是元素对的出现次数。左侧的 $r(k - 1)$ 是指,对于任意给定的元素,它在 $r$ 个区组中出现,而在每个区组中与它一起出现的其他元素有 $k - 1$ 个,因此它与其他元素组成的对有 $r(k - 1)$ 对。
右侧的 $\lambda(v - 1)$ 是指,设计中任意两个不同元素作为一对出现的总次数。由于有 $v$ 个元素,任何一个特定的元素都可以与其他 $v - 1$ 个元素组成对。因为每一对元素恰好出现 $\lambda$ 次,所以总共有 $\lambda(v - 1)$ 对。
这个等式确保了设计中的每一对元素都有相同的重复次数,即每一对元素都平均分布在所有的区组中。
这些条件确保了设计的“平衡性”。
Steiner三元系(Steiner Triple System,简称STS)是一种特殊类型的平衡不完全区组设计(BIBD),其中每个区组(或块)包含恰好3个元素,而且任意两个元素恰好在一个区组中出现一次。这种设计的参数满足 $k=3$ 和 $\lambda=1$。
Steiner三元系的一个经典示例是当 $v=7$ 时的情况,这个系统也被称作 $S(2, 3, 7)$。在这个系统中,有7个元素,每个区组(或称块)包含3个元素,而且每两个元素恰好在一个区组中出现一次。
下面是一个 $S(2, 3, 7)$ Steiner三元系的示例:
设我们的元素集合为 $\{1, 2, 3, 4, 5, 6, 7\}$,那么一个可能的区组划分为:
- $\{1, 2, 3\}$
- $\{1, 4, 5\}$
- $\{1, 6, 7\}$
- $\{2, 4, 6\}$
- $\{2, 5, 7\}$
- $\{3, 4, 7\}$
- $\{3, 5, 6\}$
六、编码简介
对称二元信道(Symmetric Binary Channel, SBC)是通信理论中的一个基本模型,用于描述一个理想化的通信环境,其中传输的二进制信息(0或1)可能会在传输过程中出错,但出错的概率是对称的,即0变成1和1变成0的概率是相同的。
信道的行为可以用一个转移概率矩阵来描述:
$$
\begin{array}{cc}
& \text{Output} \\
\text{Input} & \begin{array}{c}
0 & 1 \\
\end{array} \\
\begin{array}{c}
0 \\
1 \\
\end{array} & \left[\begin{array}{cc}
1-p & p \\
p & 1-p \\
\end{array}\right]
\end{array}
$$
最近邻解码法则(Minimum Distance Decoding)是纠错码中的一种基本解码策略,它基于码字之间的最小汉明距离来进行错误纠正。
一个具有最小汉明距离 $d$ 的码可以检测至多 $d-1$ 个错误,并可以纠正至多 $\lfloor (d-1)/2 \rfloor$ 个错误。
接收方会计算收到的码字与所有有效码字之间的汉明距离,并选择距离最小的码字作为原始码字的估计。如果最小汉明距离对应的码字是唯一的,那么解码就成功了。
举例来说,假设我们有一个简单的(7,4)汉明码,它具有最小汉明距离3。这意味着它能够纠正单个错误。如果发送的码字是1110000,而接收到的码字是1110100(第五位发生了翻转),根据最近邻解码法则,我们会比较接收到的码字与所有可能的有效码字。在这个例子中,1110000与接收到的码字1110100只有一个位的差异,而其他有效码字与接收到的码字的差异会更多。因此,我们可以判断出第五位是错误的,并将其纠正为原始码字1110000。
汉明不等式是纠错码理论中的一个基本结果,它给出了在一定条件下,可靠通信所需的最小冗余度。汉明不等式涉及到码字的长度、码字的数量以及码字之间的最小汉明距离。
假设有一个二进制线性码,其参数为 $(n, M, d)$,其中:
- $n$ 是每个码字的长度(位数)。
- $M$ 是码字的总数。
- $d$ 是码字之间的最小汉明距离。
汉明不等式表明,对于任何 $d$-错误检测和 $t$-错误纠正的码(通常 $d=2t+1$),码字的数量 $M$ 必须满足以下条件:
$$
M \cdot \sum_{i=0}^{t} \binom{n}{i} \leq 2^n
$$
这里,$\binom{n}{i}$ 表示从 $n$ 位中选择 $i$ 位的组合数,代表可能的错误模式的数量。
汉明不等式可以重新表述为关于码率和错误纠正能力的不等式。码率 $R$ 定义为每个码字中携带信息的比率,即 $R = \log_2(M)/n$,这里的 $\log_2$ 表示以2为底的对数。因此,汉明不等式也可以写成:
$$
2^{nR} \cdot \sum_{i=0}^{t} \binom{n}{i} \leq 2^n
$$
或者
$$
R \leq 1 - \frac{1}{n} \log_2\left(\sum_{i=0}^{t} \binom{n}{i}\right)
$$
汉明不等式说明了在给定的码长和纠错能力下,码率有一个上限。换句话说,如果你想要提高码的纠错能力(即增加 $t$),你必须牺牲码率(即减少 $R$),因为你需要更多的冗余位来提高纠错能力。
汉明界是一个保守的界限,实际上有些码可以达到更高的效率。
重复码是一种非常简单的纠错码,它通过简单地重复每个位来增加冗余。例如,如果我们使用一个三重复码,那么原始的二进制数据位 `1` 会被编码成 `111`,而数据位 `0` 会被编码成 `000`。这种编码方式的目的是在信道中增加冗余度,以便在接收端可以进行错误检测和纠正。
重复码的主要特点是其简单性和高度的冗余。由于每个位都被重复多次,因此即使在多个副本中有一些位发生了错误,也有可能通过投票机制(即多数表决规则)来确定原始的位是什么。例如,在三重复码中,如果接收到的是 `110`,可以假设正确的编码应该是 `111`,因为多数位是 `1`。
重复码的最小汉明距离等于重复次数,因为要将一个合法的码字变成另一个合法的码字,至少需要改变所有的重复位。因此,如果码字被重复了 $n$ 次,最小汉明距离是 $d = n$。根据纠错的基本原则,一个码可以纠正 $\lfloor (d-1)/2 \rfloor$ 个错误,所以 $n$ 重复码可以纠正 $\lfloor (n-1)/2 \rfloor$ 个错误。
例如,对于三重复码($n=3$),最小汉明距离 $d=3$,它可以纠正 $\lfloor (3-1)/2 \rfloor = 1$ 个错误。这意味着如果在三个位中只有一个位是错误的,我们可以成功地纠正它。
然而,重复码的效率非常低。如果我们重复每个位 $n$ 次,那么码率 $R$(即每个码字中信息位的比例)将是 $1/n$。这意呺着随着冗余度的增加,有效数据的传输率将显著降低。
奇偶校验码是一种简单的错误检测编码方式,它通过添加一个额外的校验位来检查数据位中的错误。奇偶校验码可以是偶校验或奇校验:
- **偶校验**:校验位设置为使得整个码字(包括数据位和校验位)中`1`的总数为偶数。
- **奇校验**:校验位设置为使得整个码字中`1`的总数为奇数。
奇偶校验码通常用于串行传输中,它可以检测出一个码字中的单个比特错误。如果两个或两个以上的比特发生错误,偶数个错误可能会相互抵消,导致奇偶校验码无法检测到错误。
例如,假设我们有一个四位的数据 `1011`,我们想要添加一个偶校验位:
- **偶校验**:由于`1011`中有三个`1`,为了使得总数为偶数,我们需要添加一个`1`作为校验位,编码后的码字为`10111`。
如果我们想要添加一个奇校验位,那么情况会有所不同:
- **奇校验**:由于`1011`中已经有三个`1`,总数是奇数,我们需要添加一个`0`作为校验位,编码后的码字为`10110`。
奇偶校验码的主要优点是简单和易于实现,但它只能检测奇数个错误,并且不能提供错误纠正的功能。对于需要更高可靠性的系统,通常会使用更复杂的错误检测和纠正码。
线性码是一种线性纠错码,它的编码过程可以用矩阵乘法来描述。线性码的两个重要组成部分是生成矩阵(Generator Matrix)和校验矩阵(Parity-Check Matrix)。
生成矩阵是一个 $k \times n$ 的矩阵(其中 $k$ 是信息位数,$n$ 是码字长度),用于将 $k$ 位的信息序列转换为 $n$ 位的码字。生成矩阵通常记为 $G$,它的行构成了码空间的一组基。在生成矩阵中,通常包含一个 $k \times k$ 的单位矩阵和一个 $k \times (n-k)$ 的校验部分。
一个线性码的生成矩阵可以表示为:
$$
G = [I_k | P]
$$
其中 $I_k$ 是一个 $k \times k$ 的单位矩阵,$P$ 是一个 $k \times (n-k)$ 的矩阵,包含了用于生成校验位的信息。
要编码一个信息序列,你可以将信息向量 $u$(一个 $1 \times k$ 的向量)与生成矩阵 $G$ 相乘,得到码字 $v$:
$$
v = u \cdot G
$$
校验矩阵是一个 $(n-k) \times n$ 的矩阵,用于检测码字中的错误。它通常记为 $H$,并且满足以下条件:
$$
H \cdot G^T = 0
$$
这意味着任何合法的码字与校验矩阵相乘的结果都是零向量。校验矩阵可以表示为:
$$
H = [-P^T | I_{n-k}]
$$
其中 $I_{n-k}$ 是一个 $(n-k) \times (n-k)$ 的单位矩阵,$P^T$ 是生成矩阵中 $P$ 部分的转置。
当接收到一个码字 $v$ 时,可以通过计算 $s = v \cdot H^T$ 来得到一个称为**综合校验向量**(或**错误综合向量**)的向量 $s$。如果 $s$ 是零向量,则码字没有错误;如果 $s$ 不是零向量,则码字可能有错误,且 $s$ 提供了关于错误位置的信息。
对于任何线性码,其生成矩阵 $G$ 和校验矩阵 $H$ 必须满足:
$$
G \cdot H^T = 0
$$
这意味着生成矩阵和校验矩阵是正交的。这也意味着任何合法的码字 $v$(由 $v = uG$ 生成)在与校验矩阵相乘时,结果都是零向量:
$$
vH^T = (uG)H^T = u(GH^T) = u \cdot 0 = 0
$$
汉明码(Hamming Code)是一种线性纠错码,由理查德·汉明(Richard Hamming)在20世纪50年代发明。汉明码是一种单错误纠正码,意味着它可以检测并纠正一位错误。
汉明码的构造涉及到生成矩阵($G$)和校验矩阵($H$)。汉明码的校验矩阵通常具有特殊的结构,使得任何两列的二进制表示都不相同,这是为了确保每个位模式都能唯一地指示出错误的位置。
一个典型的汉明码的校验矩阵 $H$ 会包含所有非零的 $r$ 位二进制数,通常按照某种顺序排列。例如,对于 $(7,4)$ 汉明码,校验矩阵 $H$ 和生成矩阵 $G$ 分别为:
$$
H = \begin{bmatrix}
1 & 0 & 1 & 0 & 1 & 0 & 1 \\
0 & 1 & 1 & 0 & 0 & 1 & 1 \\
0 & 0 & 0 & 1 & 1 & 1 & 1 \\
\end{bmatrix}
$$
$$
G = \begin{bmatrix}
1 & 0 & 0 & 0 & 0 & 1 & 1 \\
0 & 1 & 0 & 0 & 1 & 0 & 1 \\
0 & 0 & 1 & 0 & 1 & 1 & 0 \\
0 & 0 & 0 & 1 & 1 & 1 & 1 \\
\end{bmatrix}
$$
在这里,$H$ 的每一列都是从 $1$ 到 $7$ 的二进制表示(不包括全零列),而 $G$ 的后三列(校验位)是 $H$ 的转置。
当接收到一个码字时,可以通过计算综合校验向量 $s = vH^T$ 来检测并可能纠正错误。如果 $s$ 是非零向量,则它的二进制表示指示了错误位的位置。例如,如果 $s = [0, 1, 1]$,则错误发生在第三位(从右边开始计数,从1开始)。
BCH码(Bose-Chaudhuri-Hocquenghem码)是一类多错误纠正的循环码。BCH码是由Raj Chandra Bose、Dwarkadas Pralhad Chaudhuri和Alexis Hocquenghem分别独立发现的。它们可以设计成纠正多个错误,并且在数字通信和数据存储系统中广泛使用。BCH码是汉明码的一种扩展,可以处理多于一位的错误。
一个BCH码通常表示为BCH(n, k, t),其中:
- $n$ 是码字的长度(总位数)。
- $k$ 是信息位的数量。
- $t$ 是码能够纠正的错误的位数。
对于给定的码长 $n$ 和错误纠正能力 $t$,BCH码的构造主要是基于有限域(Galois Field)上的多项式运算。构造过程涉及到生成一个特定的生成多项式 $g(x)$,它是有限域上的最小多项式的乘积,这些最小多项式与能够纠正的错误位数 $t$ 相关。
7BCH一般指BCH(7,4,1)。
(1)构造过程(简化版)
- 选择生成多项式**: 对于7位BCH码,我们选择一个能够生成长度为7的码字的多项式。例如,$g(x) = x^3 + x + 1$。
- 创建码字**:
- 对于每组4位信息,我们创建一个多项式,比如信息`1011`对应的多项式是$i(x) = x^3 + x + 1$。
- 然后,我们将这个多项式乘以生成多项式$g(x)$,得到一个度数不超过6的多项式$c(x)$,这个多项式对应于7位码字。
(2)错误检测和纠正(简化版)
- 接收**: 接收到一个可能含有错误的7位码字。
- 检测**: 用接收到的码字多项式$r(x)$除以生成多项式$g(x)$,计算余数。
- 如果余数为0,认为没有错误。
- 如果余数不为0,说明至少有一位错误。
- 纠正**: 对于单错误纠正的7位BCH码,我们可以简单地通过观察余数确定错误位的位置,并将其翻转来纠正错误。
七、组合算法简介
归并排序(Merge Sort)是一种高效的排序算法,采用分治法(Divide and Conquer)的一个典型应用。其基本思想是将两个已经排序的序列合并成一个序列,也就是说,归并排序算法将大问题分解成小问题处理,然后再将小问题的答案“合并”起来解决大问题。
function mergeSort(array)
if length(array) > 1
middle <- length(array) / 2
leftArray <- array[1...middle]
rightArray <- array[middle+1...end]
mergeSort(leftArray)
mergeSort(rightArray)
merge(leftArray, rightArray, array)
function merge(leftArray, rightArray, array)
i <- 0, j <- 0, k <- 0
while i < length(leftArray) and j < length(rightArray)
if leftArray[i] < rightArray[j]
array[k++] <- leftArray[i++]
else
array[k++] <- rightArray[j++]
while i < length(leftArray)
array[k++] <- leftArray[i++]
while j < length(rightArray)
array[k++] <- rightArray[j++]
快速排序(Quick Sort)是由东尼·霍尔(Tony Hoare)在1960年提出的一种排序算法,也是一种非常高效的排序方法。它同样使用分治法策略来进行排序,但与归并排序不同的是,快速排序通常是原地排序,即不需要额外的存储空间。
function quickSort(array, low, high)
if low < high
pivotIndex <- partition(array, low, high)
quickSort(array, low, pivotIndex - 1)
quickSort(array, pivotIndex + 1, high)
function partition(array, low, high)
pivot <- array[high]
i <- (low - 1)
for j <- low to high - 1
if array[j] < pivot
i <- i + 1
swap array[i] with array[j]
swap array[i + 1] with array[high]
return (i + 1)
Ford–Johnson排序法,也被称为Merge-Insertion排序,是一种效率较高的比较排序算法。它由Lester R. Ford, Jr.和Selmer M. Johnson在1959年发明。这种算法是一种混合排序算法,结合了插入排序和“合并”策略,目的是减少比较的次数。
Ford–Johnson排序法的主要思想是将数据分成多个小组,然后使用插入排序对每个小组进行排序。之后,使用一种特殊的合并过程将这些小组合并起来。这个合并过程不同于传统的归并排序,它是通过构建一个特殊的数据结构(通常是一棵树),来确定插入位置,从而减少所需的比较次数。
这个算法的性能介于$O(n \log n)$和$O(n \log \log n)$之间,因此在理论上要优于传统的$O(n \log n)$排序算法(如快速排序、堆排序和归并排序),但在实际应用中,由于其复杂性和所需的额外开销,它并不如这些更简单的$O(n \log n)$算法流行。
(1)排序后选择
def find_kth_element_sorting(arr, k):
arr.sort()
return arr[k-1] # assuming k is not zero-indexed
(2)快速选择
def quickselect(arr, k):
if len(arr) == 1 and k == 1:
return arr[0]
pivot = arr[len(arr) // 2]
lows = [el for el in arr if el < pivot]
highs = [el for el in arr if el > pivot]
pivots = [el for el in arr if el == pivot]
if k <= len(lows):
return quickselect(lows, k)
elif k <= len(lows) + len(pivots):
return pivots[0]
else:
return quickselect(highs, k - len(lows) - len(pivots))
(3)堆选择
快速傅里叶变换(Fast Fourier Transform,FFT)是一种算法,它能够快速计算离散傅里叶变换(Discrete Fourier Transform,DFT)及其逆变换。DFT是一种将时域信号转换为频域信号的数学变换,而FFT则是计算这种变换的一种高效手段。
(1)离散傅里叶变换(DFT)
DFT将一个时域信号,可以是实数或者复数序列,转换成频域的复数序列。对于长度为$N$的序列$x[n]$,其DFT定义为:
$$
X[k] = \sum_{n=0}^{N-1} x[n] \cdot e^{-\frac{i 2\pi}{N} kn}, \quad k = 0, 1, \ldots, N-1
$$
这里,$X[k]$是复数形式的频域表示,其中每个元素$X[k]$对应于输入信号在频率$k$处的幅度和相位信息。$i$是虚数单位,$k$是频率索引,$n$是时域索引。
(2)快速傅里叶变换
快速傅里叶变换(FFT)的计算过程可以通过多种不同的算法实现,其中最常见和最著名的是Cooley-Tukey算法。以下是该算法的一个概述,它描述了如何将一个长度为$N$的序列的DFT计算分解为更小的DFT计算。
假设我们想计算一个长度为$N$的序列$x[n]$的DFT,且$N$是2的幂(即$N=2^m$,其中$m$是整数)。
- 分解阶段
FFT算法首先将原始序列分为两个部分:
- 偶数索引序列($x[0], x[2], x[4], \ldots, x[N-2]$)
- 奇数索引序列($x[1], x[3], x[5], \ldots, x[N-1]$)
这可以表示为两个子序列$x_{\text{even}}[n]$和$x_{\text{odd}}[n]$,每个子序列的长度都是$N/2$。
- 征服阶段
接下来,算法递归地对这两个子序列应用FFT,计算它们的DFT。由于每次递归都将序列长度减半,这个过程会在$log_2(N)$步之后完成。在递归的最底层,将计算长度为1的DFT,即序列本身。
- 合并阶段
一旦计算出了偶数和奇数子序列的DFT,就可以使用蝶形运算将它们组合起来得到原序列的DFT。蝶形运算是一种简单的数学操作,用于更新和合并DFT结果。
对于每个$k$(其中$k=0,1,\ldots,N/2-1$),我们有:
$$
\begin{align*}
X[k] &= X_{\text{even}}[k] + e^{-\frac{i 2\pi}{N} k} \cdot X_{\text{odd}}[k] \\
X[k + N/2] &= X_{\text{even}}[k] - e^{-\frac{i 2\pi}{N} k} \cdot X_{\text{odd}}[k]
\end{align*}
$$
这里,$X[k]$是最终的DFT结果,$X_{\text{even}}[k]$和$X_{\text{odd}}[k]$分别是偶数和奇数子序列的DFT结果。
DFS(深度优先搜索,Depth-First Search)是一种用于遍历或搜索树或图的算法。在树中,算法沿着一个分支深入,直到这个分支不能再继续下去为止,然后回溯到上一个分岔点,可能会继续沿另一个分支深入,如此循环,直到所有的节点都被访问过为止。
(1)递归实现
在递归实现中,DFS从一个起始节点开始,访问并标记该节点,然后对每个未访问的相邻节点,递归地调用DFS过程。
def dfs_recursive(graph, vertex, visited=None):
if visited is None:
visited = set()
visited.add(vertex)
print(vertex) # 可以在这里执行对节点的操作,例如打印
for neighbor in graph[vertex]:
if neighbor not in visited:
dfs_recursive(graph, neighbor, visited)
return visited
(2)非递归实现(使用栈)
非递归实现使用一个栈来模拟递归过程。算法从起始节点开始,将节点放入栈中,并在每次迭代中从栈中取出一个节点,访问它,并将其未访问的相邻节点入栈。
def dfs_iterative(graph, start):
visited = set()
stack = [start]
while stack:
vertex = stack.pop()
if vertex not in visited:
print(vertex) # 可以在这里执行对节点的操作,例如打印
visited.add(vertex)
# 将所有未访问的相邻节点入栈
for neighbor in reversed(graph[vertex]): # 使用reversed保持与递归版本相同的访问顺序
if neighbor not in visited:
stack.append(neighbor)
return visited
BFS(广度优先搜索,Breadth-First Search)是一种用于遍历或搜索树或图的算法。与深度优先搜索不同,BFS是层层推进的过程.
在BFS的实现中,算法从一个起始节点开始,访问并标记该节点,然后将其所有未访问的邻居节点加入到一个队列中。然后算法从队列中取出一个节点,访问并标记它的所有未访问邻居,并将这些邻居加入队列。这个过程一直持续到队列为空,或者找到目标节点。
from collections import deque
def bfs(graph, start):
visited = set() # 创建一个集合来存储访问过的节点
queue = deque([start]) # 创建一个队列,并将起始节点加入队列
while queue:
vertex = queue.popleft() # 从队列中取出一个节点
if vertex not in visited:
print(vertex) # 可以在这里执行对节点的操作,例如打印
visited.add(vertex) # 标记节点为已访问
# 将所有未访问的相邻节点加入队列
for neighbor in graph[vertex]:
if neighbor not in visited:
queue.append(neighbor)
return visited
在$\alpha\beta$剪枝中:
- $\alpha$代表Maximizer(试图得分最高的玩家)在其搜索过程中已经找到的**最好得分**。这个得分是Maximizer玩家可以确保的,因为它是他们已经考虑过的所有走法中最好的结果。
- $\beta$代表Minimizer(试图让对手得分最低的玩家)在其搜索过程中已经找到的**最坏得分**。这个得分是Minimizer玩家可以确保的,因为它是他们已经考虑过的所有走法中最坏的结果。
现在,让我们来看一个简化的例子:
- 假设Maximizer正在考虑一个走法,此时他们已经找到了一个可以得到10分的走法。那么$\alpha$就是10,因为这是Maximizer知道的最低保证分数。
- 同时,Minimizer也在考虑一个走法,而他们已经找到了一个能让对手得到最多5分的走法。那么$\beta$就是5,因为这是Minimizer知道的对手能得到的最高分数。
在搜索过程中,如果Maximizer发现任何一个走法可能导致得分低于10分,他们就可以忽略这个走法,因为他们已经有了一个更好的选择(至少得10分)。同样,如果Minimizer发现任何一个走法可能导致对手得分超过5分,他们也可以忽略这个走法,因为他们已经有了一个更好的选择(最多让对手得5分)。
$\alpha\beta$剪枝就是基于这样的逻辑来排除掉那些不会影响最终决策的走法,从而减少需要考虑的走法数量,加快搜索速度。
function alphabeta(node, depth, α, β, maximizingPlayer)
if depth == 0 or node is a terminal node
return the heuristic value of node
if maximizingPlayer
value := -∞
for each child of node
value := max(value, alphabeta(child, depth - 1, α, β, false))
α := max(α, value)
if α ≥ β
break (* β剪枝 *)
return value
else
value := ∞
for each child of node
value := min(value, alphabeta(child, depth - 1, α, β, true))
β := min(β, value)
if β ≤ α
break (* α剪枝 *)
return value
- 如果是Maximizer的回合,函数会试图更新`α`值,因为它寻找的是更高的得分。如果发现`α`大于或等于`β`,则进行$\beta$剪枝,因为Minimizer不会允许游戏走到这个节点。
- 如果是Minimizer的回合,函数会试图更新`β`值,因为它寻找的是更低的得分。如果发现`β`小于或等于`α`,则进行$\alpha$剪枝,因为Maximizer不会允许游戏走到这个节点。
分支界定法(Branch and Bound)是一种用于解决优化问题的算法框架,尤其是在决策树或搜索树中寻找最优解的问题。这种方法通常用于解决组合优化问题,如旅行商问题(TSP)、整数线性规划问题等。分支界定法通过系统地枚举所有可能的候选解,并使用界限技术来避免枚举所有可能性,从而减少问题的求解规模。
分支界定法包括两个主要的步骤:分支(Branching)和界定(Bounding)。
(1)分支(Branching):这个步骤将问题分解为多个较小的子问题。这些子问题代表原问题的一个子集,它们的集合覆盖了原问题的所有可能解。
(2)界定(Bounding):对于每个子问题,算法计算一个界限值,这个值是该子问题所有可能解的最优解的上界或下界。这个界限用于判断是否可以从进一步的考虑中排除某个子问题:
- 如果一个子问题的上界比已知的最优解的值还要差(对于最大化问题),或者下界比已知的最优解还要好(对于最小化问题),那么这个子问题就不可能包含比当前最优解更好的解,因此可以被剪枝,不再进一步考虑。
- 如果子问题的界限是有希望的(即对于最大化问题,上界优于当前最优解;对于最小化问题,下界还没有最优解那么差),那么这个子问题就会被进一步分支。
最小生成树(Minimum Spanning Tree, MST)问题是指在一个加权无向图中找到一个权值之和最小的生成树,即包含所有顶点且边的权值总和最小的树。生成树是原图的一个子图,包含图中所有顶点,且形成一个无环连通子图。
Kruskal算法是解决最小生成树问题的一种算法,它的基本思想是按照边的权重从小到大的顺序选择边,构造最小生成树。Kruskal算法是一种贪心算法。
function Kruskal(graph):
forest = new DisjointSet() # 并查集用于管理顶点集合
MST = [] # 存储最小生成树的边
edges = sort(graph.edges, by weight) # 按边的权值排序
for each vertex in graph.vertices:
forest.make_set(vertex) # 初始化并查集,每个顶点一个集合
for edge in edges:
u, v = edge.vertices
if forest.find_set(u) != forest.find_set(v): # 如果u和v不在同一个集合中
MST.append(edge) # 将边加入到最小生成树中
forest.union(u, v) # 合并u和v所在的集合
return MST
霍夫曼树(Huffman Tree),也称为最优二叉树,是一种特殊的二叉树,主要用于数据压缩中的霍夫曼编码(Huffman Coding)。霍夫曼编码是一种编码方法,用于无损数据压缩,它根据每个字符在待编码的数据中出现的频率来构造不等长的编码。频率高的字符使用较短的编码,频率低的字符使用较长的编码,这样可以减少整个数据的平均编码长度,达到压缩数据的目的。
构建霍夫曼树的步骤如下:
(1)统计频率:首先统计每个字符在数据中出现的频率。
(2)初始化森林:为数据中的每个唯一字符创建一个节点,并将这些节点作为一个森林的树(每棵树只有一个节点)。
(3)构建树:然后执行以下步骤,直到森林中只剩下一棵树:
- 从森林中选择两棵根节点拥有最小权值的树(权值通常是节点中字符出现的频率)。
- 创建一个新的内部节点,其权值为两个选中树根节点权值之和。
- 将选中的两棵树作为新创建的内部节点的子树,其中一个成为左子树,另一个成为右子树。
- 将新的内部节点加入森林中,并从森林中移除之前选中的两棵树。
(4)生成编码:最终,森林中剩下的单棵树就是霍夫曼树。通过从根节点到每个叶子节点的路径来确定每个字符的编码,路径中左分支代表“0”,右分支代表“1”。
在多段判决问题中,决策者需要在不同的时间点做出一系列的选择,而每一个选择都可能依赖于当前的状态和之前的决策。这些决策通常需要在不确定性的环境中进行,例如在不完全知道未来事件如何发展的情况下。