离散数学(02324)

184 阅读4分钟

记录学习离散数学的过程

喂了GTP一些历届真题, 需要的可以试试

集合

1. 交集(Intersection) ABA \cap B

  • 定义:交集表示两个集合的公共元素,即属于集合 A 且属于集合 B 的所有元素。
  • 记号:ABA∩B
  • 例子:如果 A={1,2,3}A = \{1, 2, 3\}B={2,3,4}B=\{2,3,4\} ,那么 AB={2,3}A \cap B = \{2, 3\}

2. 并集(Union) ABA \cup B

  • 定义:并集表示两个集合的所有元素,即属于集合 A 或属于集合 B(或属于两者)的所有元素。
  • 记号:ABA \cup B
  • 例子:如果 A={1,2,3}B={2,3,4}A=\{1,2,3\},B=\{2,3,4\},那么 AB={1,2,3,4}A∪B=\{1,2,3,4\}

3. 差集(Difference) ABA \setminus B

  • 定义:差集表示属于集合 A 但不属于集合 B 的所有元素。
  • 记号:ABA \setminus B
  • 例子:如果 A={1,2,3}B={2,3,4}A = \{1, 2, 3\},B = \{2, 3, 4\},那么 AB={1}A \setminus B = \{1\}(集合 A 中去掉了 B 中的元素)。

4. 补集(Complement) AcA^c

  • 定义:补集表示不属于集合 A 的所有元素。通常补集是针对某个全集 U 来定义的,即 Ac=UAA^c = U \setminus A
  • 记号:AcA^cA\overline{A}
  • 例子:如果全集U={1,2,3,4,5}U = \{1, 2, 3, 4, 5\},集合 A={1,2}A = \{1, 2\},那么 Ac={3,4,5}A^c = \{3, 4, 5\}

5. 对称差(Symmetric Difference) ABA \triangle B

  • 定义:对称差表示属于集合 A属于集合 B不属于两者的公共部分的元素。换句话说,它是两个集合差集的并集:(AB)(BA)(A \setminus B) \cup (B \setminus A)
  • 记号:ABA \triangle B
  • 例子:如果 A={1,2,3}A = \{1, 2, 3\}B={2,3,4}B = \{2, 3, 4\},那么 AB={1,4}A \triangle B = \{1, 4\}

6. 笛卡尔积(Cartesian Product) A×BA \times B

  • 定义:笛卡尔积是所有有序对 (a,b)(a,b),其中 aAbBa∈A 且 b ∈ B 的集合。它表示两个集合的所有可能的组合
  • 记号:A×BA \times B
  • 例子:如果 A={1,2}A = \{1, 2\}B={x,y}B = \{x, y\},那么 A×B={(1,x),(1,y),(2,x),(2,y)}A \times B = \{(1, x), (1, y), (2, x), (2, y)\}

什么是命题公式?举例说明

  • 命题公式是由一个或多个命题通过逻辑连词(如“与” (∧)、“或” (∨)、“非” (¬)、“如果...则...” (→) 等)组成的表达式,用来表达逻辑关系。
  • 举例 :
    1. 命题P性别是男, 命题B是命题P的父亲
    2. 公式 P ^ B 表示 P和B的性别都是男

如何判断一个公式为永真式

  • 永真式是指在所有可能的情况下,逻辑公式的值总是为真的公式。不论命题中的各个成分如何,永真式的结果始终为真。
  • 公式P∨¬P为永真式,因为这个公式表达了 P为真或者P为假
  • 因此,P∨¬P 这个公式表示的是“P 为真或者 P 为假”,即命题 P 要么为真,要么为假,这叫做排中律
  • 排中律意味着:对于任何命题 P,它要么为真,要么为假,所以公式 P∨¬P 永远为真,称为永真式

真值表

  • P=真,Q=真
  • P=真,Q=假
  • P=假,Q=真
  • P=假,Q=假

常用推导公式

1. 交换律 (Commutative Law)
  • P∨Q≡Q∨P
  • P∧Q≡Q∧P
2. 结合律 (Associative Law)
  • (P∨(Q∨R))≡((P∨Q)∨R)
  • (P∧(Q∧R))≡((P∧Q)∧R)
3. 分配律 (Distributive Law)
  • P∧(Q∨R)≡(P∧Q)∨(P∧R)
  • P∨(Q∧R)≡(P∨Q)∧(P∨R)
4. 德摩根律 (De Morgan’s Law)
  • ¬(P∨Q)≡(¬P∧¬Q)
  • ¬(P∧Q)≡(¬P∨¬Q)
5. 双重否定律 (Double Negation Law)
  • ¬(¬P)≡P
6. 吸收律 (Absorption Law)
  • P∨(P∧Q)≡P
  • P∧(P∨Q)≡P
7. 恒等律 (Identity Law)
  • P∨False≡P
  • P∧True≡P
8. 零律 (Domination Law)
  • P∨True≡True
  • P∧False≡False
9. 排中律 (Law of Excluded Middle)
  • P∨¬P≡True
10. 矛盾律 (Law of Contradiction)
  • P∧¬P≡False
11. 蕴含的等价形式 (Implication Law)
  • P→Q≡¬P
12. 对合律 (Involution Law)
  • P≡P
13. 条件律 (Implication Law)
  • P→Q≡¬P∨Q

什么是“主范式”,包括主合取范式和主析取范式。

  • 主范式(Normal Form)是逻辑表达式的一种标准化形式,通常分为两种:主合取范式主析取范式
  1. 主合取范式(Conjunctive Normal Form, CNF):是用“与” (∧) 连接多个“或” (∨) 表达式的范式。每个子表达式称为析取式。例如:(P∨Q)∧(¬P∨R)
  2. 主析取范式(Disjunctive Normal Form, DNF):是用“或” (∨) 连接多个“与” (∧) 表达式的范式。每个子表达式称为合取式。例如:(P∧Q)∨(¬P∧R)
  • 小项是**命题变元或其否定通过合取(∧)**连接的形式,用于合取范式。
  • 大项是**命题变元或其否定通过析取(∨)**连接的形式,用于析取范式。

例子

  • 推导以下公式的主合取范式(CNF)和主析取范式(DNF):P→Q
  • 主析(P^Q)∨(¬P^¬Q) 它表示当 P 和 Q 同时为真,或者 P 和 Q 同时为假时,公式的值为真。
  • 主合取范式 (¬P∨Q)∧(P∨¬Q) 只有在这两个条件都为真时,整个表达式为真

连结词完备集

  • 连结词完备集 是指在逻辑系统中,一组逻辑运算符(连结词)是足够表达任何命题公式的组合。比如,常见的连结词有 "与"(∧)、"或"(∨)、"非"(¬)、"蕴含"(→)等。
  • 某些小的连结词集合(比如{¬, ∧} 或 {¬, ∨})就可以构成完备集,意味着这些连结词可以表达所有其他逻辑运算。这就是所谓的逻辑连结词的“完备性”。

等价关系

  • 等价关系是一种在集合上的特殊关系,它把集合中的元素分成多个等价类。这个等价关系满足三个基本的性质:自反性、对称性和传递性。

等价关系的定义:

  • 设 A 是一个集合,R 是 A 上的一个二元关系(即,集合 A 中的元素两两之间的关系)。如果这个关系满足以下三个性质,我们就称它为等价关系
  1. 自反性:对于集合中的任意元素 a,都有 aRa。换句话说,任何一个元素都与自身有关系。

    • 例如,"等于"是一个自反关系,因为每个数都等于自己,如 5=5。
  2. 对称性:如果 aRb,那么 bRa 也成立。即,如果 a 和 b 之间有关系,那么 b 和 a 之间也有相同的关系。

    • 例如,"等于"也是一个对称关系,如果 5=7,那么 7=5。
  3. 传递性:如果 aRb 并且 bRc,那么 aRc 也成立。换句话说,关系可以通过中间元素传递。

    • 例如,"等于"也是一个传递关系。如果 a=b 且 b=c,那么 a=c。

偏序关系

  • 偏序关系是一种二元关系,它定义了元素之间的一种部分顺序。这种顺序关系具有以下三个基本性质:
  1. 自反性:对于任何元素 a,总是 a≤a
  2. 反对称性:如果 a≤b 且 b≤a,则 a=b。
  3. 传递性:如果 a≤b 且 b≤c,则 a≤c

如何在集合上定义偏序关系

  1. 选择集合:选择一个集合 A,例如 A={1,2,3}。

  2. 定义关系:在集合 A上定义一个符合自反性、反对称性和传递性的二元关系。比如可以定义一个“\leq”关系:

    • 1≤1, 2≤2, 3≤3(自反性)
    • 1≤2, 2≤3 (传递性)

    关系可以写为:

    R={(1,1),(2,2),(3,3),(1,2),(2,3),(1,3)}

  • 验证自反性:每个元素都与自己相关联(a≤a)。

  • 验证反对称性:如果 a≤b 且 b≤a,则 a=b。(例如,1≤2且 2≤1 不成立,反对称性成立。)

  • 验证传递性:如果 a≤b且 b≤c,则 a≤c。(例如,1≤2 和 2≤3 推导出 1≤3)

全序关系

  • 全序关系是指在一个集合上的二元关系,该关系满足以下条件:
  1. 自反性:对于任何元素 a,总是 a≤a
  2. 反对称性:如果 a≤b 且 b≤a,则 a=b。
  3. 传递性:如果 a≤b 且 b≤c,则 a≤c
  4. 全性(Totality 或 Comparability) :对于集合中的任意两个元素 a 和 b,要么 a≤b,要么 b≤a(即,所有元素都是可以比较的)

全序关系与偏序关系的区别:

  • 全序关系要求所有的元素都可以进行比较(即满足全性),即集合中的任意两个元素之间必须存在顺序关系(a≤b或 b≤a)。这意味着在全序关系下,所有元素是线性排序的。
  • 偏序关系则没有要求所有元素之间都能进行比较,它只需要满足自反性、反对称性和传递性,但不要求全性。也就是说,在偏序关系下,可能存在一些元素之间是不可比较的。

对称关系

  • 对称关系 (Symmetric Relation) : 对称关系是指,如果集合中的元素 a 与 b 存在关系 R(a,b),那么反过来 R(b,a) 也必须成立。
  • 例子:在集合 A={1,2,3}上,如果 R={⟨1,2⟩,⟨2,1⟩,⟨3,3⟩}, ,则 R 是对称关系,因为每对存在的关系都可以反过来成立。

反自反关系

  • 反自反关系 (Anti-reflexive Relation) : 反自反关系要求在集合中,任何元素都不与自身存在关系
  • 数学表达为:

对于任何a∈A,⟨a,a⟩∉R

例子:在集合 A={1,2,3} 上,如果 R={⟨1,2⟩,⟨2,3⟩},则 R 是反自反关系,因为没有任何元素与自身存在关系。

成真指派

-命题公式的成真指派”指的是一种逻辑公式在特定的命题变元取值下是否为“真”。每一个命题变元(例如 P、Q、R)在逻辑上可以有两个值:真(1)或假(0)。成真指派就是那些使得整个命题公式结果为真的命题变元的取值组合。

例如:

考虑命题公式 (P∧Q)→R

  • 命题变元 P、Q、R 都是可以为真或假的命题。

  • 指派:我们可以用 0 表示假,用 1 表示真。每个命题变元 P、Q、R 的取值组合就叫做“指派”。

    比如:

    • P=0,Q=0,R=0 可以写为指派 000。
    • P=1,Q=1,R=0 可以写为指派 110。

如何理解公式:

(PQ)R(P∧Q)→R 这个公式可以逐步解释为:

  • P∧Q 表示 P 和 Q 同时为真时才为真,其他情况都为假。
  • → 表示“如果...那么...”的关系,即如果左边的公式为真,则右边的结果必须为真。

如何寻找成真指派:

我们需要找到那些使得整个公式为 真的 取值组合。也就是,找出哪些 P、Q、R 的组合可以使公式 (P∧Q)→R 的结果为真。

我们来看看不同的指派组合对公式 (P∧Q)→R的影响:

PQRP∧Q(P∧Q)→R
00001
00101
01001
01101
10001
10101
11010
11111

总结:

  • 当 P=1,Q=1 且 R=0,公式为假。这是唯一的情况。
  • 其他情况下,公式都是 的。

因此,成真指派是所有使公式结果为真的那些 P、Q、R 的取值组合。对于本公式,成真指派是所有组合除了 110 这一种。

为什么“前提为假”时整个条件命题为真?

在经典逻辑中,条件命题 P→Q 的定义是基于真值表的。这个定义规定了当 P 为假时,P→Q 总是为真。这个规则的目的是保证逻辑系统的“完备性”和一致性,使得推理可以正常进行。

其逻辑基础是这样的:

  • 蕴含命题 P→Q 表示的是一种“承诺”:只要 P 为真,Q 就必须为真。
  • 如果 P 是假的,即前提不成立,那么无论 Q 是什么(真或假),整个命题不再承担这个“承诺”,因此整个命题被认为是自动为真的。
  • 这是一种 '无责任规则':如果前提条件不成立,那么我们就没有义务再去验证结论的真假。由于我们不需要对结果负责,系统就把这种情况定义为“真”,以保证逻辑推理的继续。

定义域(Domain)

  • 定义:定义域是函数的输入范围,也就是可以代入函数的所有值的集合。

  • 简单理解:函数可以接受哪些值,这些值就构成了定义域。

  • 假设有一个函数 f(x)=1/x,它代表的是“1 除以 x”的结果。问题来了:

  • 如果你将 x=0代入,那么这个函数的结果是没有定义的,因为除以零是非法的

  • 因此,函数的定义域必须去掉 x=0的情况,这样我们就清楚地知道函数的输入范围是哪些。

因此,定义域限制了函数的输入值,确保只有合理的输入才能使用函数计算,防止无意义或错误的结果出现。

值域(Range)

  • 定义:值域是函数的输出范围,即函数可以得到的所有输出值的集合。
  • 简单理解:函数的输出可以是什么值,这些值构成了值域。 例如,对于函数 f(x)=x2 是正数还是负数,函数的输出 f(x) 总是非负的(因为平方后的数不会是负数)。所以,这个函数的值域是非负数 {f(x)∣f(x)≥0}。

陪域(Codomain)

  • 陪域是函数的输出的可能范围,而值域是函数实际的输出范围。陪域和值域不同之处在于:

  • 值域 是函数真正能输出的所有值。

  • 陪域 是函数可能会输出的所有值,通常由函数定义时给出。

    例如,对于函数f:ZZ,陪域是整数集合Z,但函数f(n)=n2,输出总是非负整数,这就构成了它的值域Z+例如,对于函数 f:Z→\mathbb{Z},陪域是整数集合 \mathbb{Z},但函数 f(n)=n^{2}, 输出总是非负整数,这就构成了它的值域 \mathbb{Z}^{+}。

  • 举个例子

 1.假设我们有一个函数f(x)=x+1,并且定义域为1,2,3 2.定义域:输入可以是1,2,3 3.通过代入f(1),f(2),f(3),得到的输出分别是2,3,4 4.所以,这个函数的值域是2,3,4\begin{align} \ 1. & 假设我们有一个函数 f(x)=x+1,并且定义域为 {1,2,3}。\\ \ 2. & 定义域:输入可以是 1,2,3。\\ \ 3. & 通过代入 f(1),f(2),f(3),得到的输出分别是 2,3,4。\\ \ 4. & 所以,这个函数的值域是 {2,3,4}。\\ \end{align}

假设f(x)=x2,定义域是所有整数(Z),即输入值可以是3,2,1,0,1,2,3等等。定义域Z(所有整数)值域0,1,4,9,16,25,...(所有非负整数,因为平方后的值总是非负的) 假设 f(x)=x^2,定义域是所有整数 (\mathbb{Z}), 即输入值可以是−3,−2,−1,0,1,2,3等等。\\ *定义域*:\mathbb{Z}(所有整数)\\ *值域*:{0,1,4,9,16,25,...}(所有非负整数,因为平方后的值总是非负的)

单射(Injection 或 One-to-one)

定义:如果对于任意的两个不同元素x1x2​在定义域中,f(x1)f(x2),那么这个函数就是单射。 定义:如果对于任意的两个不同元素 x1 和 x2​ 在定义域中,f(x1)≠f(x2),那么这个函数就是单射。

例子:函数f(x)=x+1是单射,因为不同的x值对应不同的f(x)值。 例子:函数 f(x)=x+1 是单射,因为不同的 x 值对应不同的f(x) 值。

满射(Surjection 或 Onto)

  • 定义:如果函数的值域(即输出的所有可能值)与陪域(函数定义时的目标集合)完全相同,那么这个函数就是满射
  • 直观理解:陪域中的每个元素至少有一个定义域中的元素与它对应,函数的输出“覆盖”了整个陪域。
  • 一个函数f:AB满射,如果对于陪域B中的每一个元素,都至少存在一个元素aA使得f(a)=b 一个函数 f:A→B 是**满射**,如果对于陪域 B 中的**每一个元素**,都至少存在一个元素 a∈A使得 f(a)=b。
  • 例子函数f(x)=x是满射(如果定义域和陪域都是实数集),因为每个实数都可以作为输出。 函数 f(x)=x是满射(如果定义域和陪域都是实数集),因为每个实数都可以作为输出。

双射(Bijective)

  • 如果一个函数既是单射又是满射,那么这个函数就是双射(Bijection)。双射函数有一个非常重要的性质,即每个输出值都有且仅有一个对应的输入值,这种函数是可逆的。

常见公式符号

y读作“存在某个y”,意思是“有一个y满足后面的条件”。x读作“对于所有的x”,意思是“对于每一个x都满足后面的条件”。mod:一个数学运算,表示**取余数**。它的含义是:将数字 a 除以 m,结果是余数。*幂集P(A)是指一个集合A的所有子集的集合函数的关键要求定义域中的每一个元素必须映射到值域中的某一个元素。但是,值域中的每一个元素不一定必须被映射到。R:表示实数集,即所有实数的集合。包括正数、负数、零、小数、分数等。Z:表示整数集,包括正负整数和零。Q:有理数集,包括可以表示为分数 a/b 的数,其中 a 和 b 都是整数且b0C:复数集,包括所有实数和虚数Rn:复数集,包括所有实数和虚数N:n维实数空间,表示由n个实数组成的有序元组(或向量)\begin{align} &\text ∃y 读作“存在某个 y”,意思是“有一个 y 满足后面的条件”。\\ &\text ∀x 读作“对于所有的 x”,意思是“对于每一个 x 都满足后面的条件”。\\ \\ &{mod}: \text{一个数学运算,表示**取余数**。它的含义是:将数字 a 除以 m,结果是余数。} \\ \\ &\text **幂集 P(A)** 是指一个集合 A 的所有**子集**的集合\\ &**函数的关键要求**:**定义域中的每一个元素必须映射到值域中的某一个元素**。但是,值域中的每一个元素不一定必须被映射到。\\ \\ \mathbb{R} &: \text{表示实数集,即所有实数的集合。包括正数、负数、零、小数、分数等。} \\ \mathbb{Z} &: \text{表示整数集,包括正负整数和零。} \\ \mathbb{Q} &: \text{有理数集,包括可以表示为分数 a/b 的数,其中 a 和 b 都是整数且} b≠0 \\ \mathbb{C} &: \text{复数集,包括所有实数和虚数} \\ \mathbb{R^n} &: \text{复数集,包括所有实数和虚数} \\ \mathbb{N} &: n-维实数空间,表示由 n 个实数组成的有序元组(或向量) \\ \end{align}

e 是一个数学常数,

  • 被称为自然对数的底数,在数学、尤其是微积分、指数函数和对数中有广泛的应用
e的定义有很多种方式,其中一种常见的定义是通过极限来定义的:e=limn(1+1n)n这意味着当n趋向于无穷大时,表达式(1+1n)n的极限值就是e另一个等价的定义来自微积分中的自然对数函数指数函数,即函数ex的导数在x=0处等于1,或者说:ddxex=ex这是一个重要的特性,使得e在微积分中的应用极为广泛。e 的定义有很多种方式,其中一种常见的定义是通过极限来定义的:\\ e = \lim_{n \to \infty} \left(1 + \frac{1}{n}\right)^n \\ 这意味着当 n 趋向于无穷大时,表达式 \left(1 + \frac{1}{n}\right)^n 的极限值就是 e。\\ 另一个等价的定义来自微积分中的**自然对数函数**和**指数函数**,即函数 e^x 的导数在 x=0 处等于 1,或者说:\\ \frac{d}{dx} e^x = e^x \\ 这是一个重要的特性,使得 e 在微积分中的应用极为广泛。

半群(Semigroup)

半群是一个集合和一个二元运算组成的代数结构。半群满足的条件是:

  • 封闭性:对于集合中的任意两个元素 a 和 b,运算 aba∗b 的结果仍然在这个集合中。

  • 结合律:对于集合中的任意三个元素 a、b、c,运算满足结合律,即 (ab)c=a(bc)(a * b) * c = a* (b * c)

  • 简单例子

  • 集合A=0,1,2A={0,1,2},二元运算是加法取模 3(即ab=(a+b)mod  3a∗b=(a+b)mod  3)。运算满足结合律,因此 A 是一个半群。

幺半群(Monoid)

  • 幺半群是在半群的基础上,再加上一个特殊的元素,这个元素称为单位元。单位元的特点是:
  • 单位元:集合中存在一个元素 e,使得对于任意的元素 a 都满足ae=ea=aa∗e=e∗a=a

简单例子

  • 集合 0,1,2{0,1,2} 加上加法取模 3 的运算,如果我们加入一个单位元,比如 0,那么它就是一个幺半群,因为0+a=a+0=a 0+a=a+0=a 对所有元素 a 都成立。

群(Group)

  • 群是在幺半群的基础上,进一步要求每个元素都必须有逆元。群需要满足以下条件:
  • 封闭性:运算的结果在集合中。
  • 结合律:运算满足结合律。
  • 单位元:存在一个单位元 e,对于任意的元素 a 都满足ae=ea=a a∗e=e∗a=a
  • 逆元:每个元素 a 都有一个逆元 b,使得 ab=ba=ea∗b=b∗a=e

简单例子

  • 整数集 Z\mathbb{Z} 在加法运算下是一个群,因为加法满足结合律、封闭性、存在单位元 0(任何整数加 0 还是自己),并且每个整数都有一个逆元(对于 1 的逆元是 −1,对于 2 的逆元是 −2)。

交换群(Abelian Group)

  • 交换群是指在群的基础上,再加上运算是可交换的。也就是说,对于群中的任意两个元素 a 和 b,都满足 ab=baa∗b=b∗a

简单例子

  • 在整数集 Z\mathbb{Z} 上的加法是可交换的,所以 Z\mathbb{Z} 加法下是一个交换群。

群、幺半群、半群的比较:

  • 半群:有封闭性和结合律。
  • 幺半群:半群再加上单位元。
  • :幺半群再加上每个元素都必须有逆元。
  • 交换群:群的基础上加上运算的可交换性。

图论

  • 图论是离散数学的一个分支,主要研究对象是图(graph) ,而“图”是由**顶点(vertex)和连接顶点的边(edge)**组成的。

图的基本组成:

  1. 顶点(Vertex) :图中的点,用来表示一个个体或对象,常用字母 VV 表示顶点集。
  2. 边(Edge) :连接两个顶点的线段,表示两个对象之间的关系,常用字母 EE 表示边集。

图的类型:

1. 无向图(Undirected Graph)
  • 无向图中的边没有方向,表示两顶点之间的关系是双向的。边 (a,b)(a,b) 表示顶点 a 和顶点 b 之间存在关系,方向不重要。
  • 无向图中的边通常用没有箭头的线来表示。
2. 有向图(Directed Graph)
  • 有向图中的边有方向,表示两个顶点之间的关系是单向的。例如,边 (ab)(a \rightarrow b) 表示从顶点 a 到顶点 b 有一条有向边,方向重要。
  • 有向图的边通常用带箭头的线表示,指示关系的方向。

无向图和有向图的区别:

  • 无向图:边没有方向,表示 a 和 b 是对等的。如果 aba \sim b,则 bab \sim a 也是成立的。
  • 有向图:边有方向,表示 a 通过箭头指向 b,但 b 不一定能回到 a。
3. 完全图(Complete Graph)
  • 完全图是每一对顶点之间都有一条边相连的图。比如在 3 个顶点的完全图中,所有顶点之间都有一条边。

度数(Degree)

  • 无向图中,一个顶点的**度数(degree)**是指与该顶点相连的边数。例如,顶点 A 有 3 条边与它相连,则顶点 A 的度数为 3。
  • 有向图中,顶点的度数分为出度(从该顶点发出的边数)和入度(指向该顶点的边数)。
例子:

假设有一个无向图 G,包含 4 个顶点 {1,2,3,4},并且顶点之间的边集为 {{(1,2),(2,3),(3,4),(4,1)\{(1, 2), (2, 3), (3, 4), (4, 1)}。这个图的边没有方向,因此是一个无向图。这个图的每个顶点都有 2 条边与其他顶点相连,表示度数为 2。

如何计算无向图中的边数?

在无向图中,如果每个顶点的度数已知,总边数可以通过下面的公式计算:

边数=顶点的总度数2\text{边数} = \frac{\text{顶点的总度数}}{2}

对于有 n 个顶点的无向图,完全图的总边数可以通过以下公式计算:

总边数=n(n1)2\text{总边数} = \frac{n(n-1)}{2}

因为每条边会连接两个顶点,所以度数的总和会是边数的两倍。

有向图中的出度和入度

有向图中,每条边都有一个明确的方向,这意味着每条边有一个起点和一个终点。所以:

  • 出度(Out-degree) :从某个顶点发出的边的数量。
  • 入度(In-degree) :指向某个顶点的边的数量。

举个例子:

设有向图 G 由 4 个顶点 {A,B,C,D}\{A, B, C, D\} 和以下有向边组成:

  • ABA \rightarrow B
  • ACA \rightarrow C
  • CDC \rightarrow D
  • BDB \rightarrow D

这个图可以画成:

rust
复制代码
A --> B --> D
 \     ^
  \   /
   -> C --> D
  • 在有向图中,边的总数与所有顶点的出度有关,因为每一条边都是从某个顶点发出。因此,可以通过出度的总和来计算边数:

总边数=所有顶点的出度之和\text{总边数} = \text{所有顶点的出度之和}

组合数学

  • 组合数学(Combinatorics)是离散数学的一个重要分支,它研究的是如何从一个有限的集合中选择排列元素。常见的组合数学问题包括排列(permutation)、组合(combination)以及计数方法。

组合数学的两大基本概念:

  1. 排列(Permutation):排列关注的是如何排列集合中的元素,顺序很重要。
    举个例子,如果我们要从 3 个字母 A,B,C中排列 2 个字母,那么不同排列可能是 AB,AC,BA,BC,CA,CB 顺序不同,排列也不同。
  2. 组合(Combination):组合关注的是如何从集合中选择元素,顺序不重要。
    比如,从字母 A,B,C中选择 2 个字母,可能的组合是 AB,AC,BC顺序不同的组合只算一种。

在组合数学中,我们常用符号C(n,k)C(n,k)来表示从 nnn 个元素中不考虑顺序地选择 k 个元素的方式数。其计算公式为:

C(n,k)=n!k!(nk)!C(n, k) = \frac{n!}{k!(n-k)!}

其中,n!n! 代表 n 的阶乘,意思是 1n×(n1)××11n \times (n-1) \times \dots \times 1

例子:
假设有 3 个苹果和 2 个橙子,问你从这些水果中选 2 个,有几种不同的选择方式?\
解法:使用组合公式:

$C(5, 2) = \frac{5!}{2!(5-2)!} = \frac{5 \times 4}{2 \times 1} = 10$

因此,有 10 种不同的选择方式。

递归关系

  • 递归关系是一种通过给定的初始条件和递归式来定义某个函数或序列的方式。递归关系描述了如何根据较小的规模来计算较大的规模,特别是在分治算法中,它用来表示算法的时间复杂度。
  • 递归关系的基本形式T(n)=aT(n/b)+O(nd)T(n)=aT(n/b)+O(n^d)

其中:

  • T(n)T(n) 表示问题规模为 n 时的时间复杂度。
  • a 是递归调用的次数(子问题的数量)。
  • n/bn/b 是每个子问题的大小。
  • O(nd)O(n^d) 是将问题分解和合并的非递归部分的时间复杂度。

假设我们有一个分治算法,其递归关系为:

T(n)=2T(n/2)+nT(n) = 2T(n/2) + n

这意味着:

  • 我们把规模为 n 的问题分解成两个规模为 n/2n/2的子问题。
  • 递归式中的 n 代表问题的分解和合并所需的时间。

如何求解递归关系

递归关系的求解通常使用以下几种方法:

  1. 递归树法:用树形结构表示递归调用的层次,然后求每层的总成本并计算树的深度。
  2. 主定理:主定理是一种用来快速求解递归关系的工具,它可以帮助我们直接确定时间复杂度。
1. 递归树法

我们通过递归树法来求解 T(n)=2T(n/2)+nT(n) = 2T(n/2) + n 的时间复杂度。

  • 第一层:问题规模为 n,它将被分解成 2 个规模为 n/2n/2 的子问题,且消耗 n 的时间。
  • 第二层:每个子问题 n/2n/2 又被分解成两个规模为 n/4n/4 的子问题,总共有 4 个子问题,每个子问题消耗 n/2n/2 的时间。
  • 第三层:每个规模为 n/4n/4 的问题再分解为两个规模为 n/8n/8 的子问题,总共有 8 个子问题,每个子问题消耗 n/4n/4 的时间。

这种分解过程会一直进行下去,直到规模减小到 1 为止。我们来计算每一层的时间复杂度:

  • 第 1 层消耗的时间是 n。
  • 第 2 层消耗的时间是 2×(n/2)=n2 \times (n/2) = n
  • 第 3 层消耗的时间是 4×(n/4)=n4 \times (n/4) = n
  • ……

可以看到,每一层的总时间消耗都是 n,树的深度是 nlog2nn\log_2 n,因为每次问题的规模都减少一半。

总时间复杂度是所有层的时间相加,即:

T(n)=n×log2n=O(nlogn)T(n) = n \times \log_2 n = O(n \log n)

2. 主定理

主定理是解决递归关系的一个非常强大的工具,它适用于形如:

T(n)=aT(n/b)+O(nd)T(n) = aT(n/b) + O(n^d)

的递归关系。主定理给出了三种情形:

  1. a>bda > b^d 时,时间复杂度是 O(nlogba)O(n^{\log_b a})
  2. a=bda = b^d 时,时间复杂度是 O(ndlogn)O(n^d \log n)
  3. a<bda < b^d 时,时间复杂度是 O(nd)O(n^d)

现在让我们应用主定理来求解 T(n)=2T(n/2)+nT(n) = 2T(n/2) + n

在这个递归关系中:

  • a=2a = 2(表示每次递归调用 2 个子问题)
  • b=2b = 2(表示问题规模每次缩小一半)
  • d=1d = 1(表示每层的额外开销为 O(n)O(n)

我们可以计算 bd=21=2b^d = 2^1 = 2bd=21=2,因为 a=bda = b^da=bd,所以根据主定理的第二种情况,时间复杂度为:

T(n)=O(ndlogn)=O(nlogn)T(n) = O(n^d \log n) = O(n \log n)

递归关系常见的例子

  • 二分查找:递归关系 T(n)=T(n/2)+O(1)T(n) = T(n/2) + O(1),时间复杂度为 O(logn)O(\log n)
  • 归并排序:递归关系 T(n)=2T(n/2)+O(n)T(n) = 2T(n/2) + O(n),时间复杂度为 O(nlogn)O(n \log n)
  • 快速排序:递归关系 T(n)=2T(n/2)+O(n)T(n) = 2T(n/2) + O(n),时间复杂度为 O(nlogn)O(n \log n)

大O符号

O 表示的是大O符号(Big-O notation),它是一种在算法分析中常用的符号,用来表示算法的时间复杂度空间复杂度。大O符号的作用是描述算法的性能,特别是当输入规模 n 趋于无限大时,算法的运行时间或空间使用量是如何增长的。

大O符号的定义:

如果一个算法的时间复杂度为T(n)T(n),并且存在常数 C 和 n0n_0,使得对于所有 0nn00n \geq n_0,都有:\\

T(n)Cf(n)T(n) \leq C \cdot f(n) \\ 那么,我们说该算法的时间复杂度是 O(f(n))O(f(n))。这里的f(n)f(n)是输入规模 n 的某种函数,它表示在最坏情况下,随着 n 的增长,算法的运行时间的增长速率。

常见的大O表示法:

以下是几种常见的时间复杂度级别,它们按增长速度从小到大排列:

  1. O(1)O(1) —— 常数时间复杂度
    无论输入大小,算法的运行时间总是常数。例如,直接访问数组中的某个元素或基本的算术运算都属于 O(1)O(1)
  2. O(logn)O(\log n) —— 对数时间复杂度
    运行时间随着输入大小的增加按对数增长。常见的例子是二分查找。
  3. O(n)O(n) —— 线性时间复杂度
    运行时间随着输入大小的增加按比例增长。例如,遍历长度为 n 的数组或链表的时间复杂度是 O(n)O(n)
  4. O(nlogn)O(n \log n) —— 线性对数时间复杂度
    比线性增长稍快,常见于分治算法,如归并排序和快速排序的最优时间复杂度。
  5. O(n2)O(n^2) —— 二次时间复杂度
    运行时间随着输入大小平方增长。例如,双重循环遍历 n 个元素的算法,通常是 O(n2)O(n^2)
  6. O(n3)O(n^3) —— 三次时间复杂度
    运行时间随着输入大小立方增长。比如,三重嵌套循环遍历 n 个元素。
  7. O(2n)O(2^n) —— 指数时间复杂度
    运行时间随着输入大小按指数增长,常见于递归算法(如解决所有子集问题的递归算法)。
  8. O(n!)O(n!) —— 阶乘时间复杂度
    运行时间随着输入大小的阶乘增长,常见于解决排列问题的算法,如暴力枚举所有可能的排列。
  • 常数时间:访问数组的第一个元素是常数时间复杂度: O(1)O(1)

  • 线性时间:遍历包含 n 个元素的数组,时间复杂度是:O(n)O(n)

  • 二分查找:在有序数组中进行二分查找,时间复杂度是: O(logn)O(\log n)

  • 归并排序:归并排序的时间复杂度是: $O(n \log n

时间复杂度增长的示意:

以下是不同复杂度的算法随着输入规模 n 增长时的表现:

  • O(1)O(1) : 不随 n 增长,运行时间是常数。
  • O(logn)O(\log n) : 增长得非常慢,即使 n 很大,运行时间也相对较小。
  • O(n)O(n) : 运行时间与 n 成正比,输入规模大时运行时间也随之增大。
  • O(nlogn)O(n \log n) : 介于线性和二次时间之间,常用于高效排序。
  • O(n2)O(n^2) : 运行时间随着 n 的平方增长,输入规模稍大时耗时明显。
  • O(2n)O(2^n)O(n!)O(n!) : 运行时间随着 n 呈指数级或阶乘级增长,输入稍大,几乎无法处理。