Keyboard shortcuts

Press ← or → to navigate between chapters

Press S or / to search in the book

Press ? to show this help

Press Esc to hide this help

附录 问题

提出问题比解决问题更重要。—— 爱因斯坦

打开一切科学的钥匙毫无异议的是问号。—— 巴尔扎克

提出正确的问题,往往等于解决了问题的大半。—— 海森堡

问题 → 猜想 → 证明 → 验证 → 定理 → 推论


一、物不知数(中国剩余定理)

《孙子算经》:今有物,不知其数。三三数之,剩二;五五数之,剩三;七七数之,剩二。问:物几何?

解法口诀:

三人同行七十稀,五树梅花廿一支,七子团圆正半月,除百零五使得知

同余方程组:

$$ \begin{cases} x \equiv 2 \pmod{3} \ x \equiv 3 \pmod{5} \ x \equiv 2 \pmod{7} \end{cases} $$

中国剩余定理: 设 $m_1, m_2, \ldots, m_k$ 两两互质,则同余方程组在模 $M = \prod m_i$ 下有唯一解。


二、鸡兔同笼

《孙子算经》:今有雉兔同笼,上有三十五头,下有九十四足,问雉兔各几何?

解法:

设鸡有 $x$ 只,兔有 $y$ 只:

$$ \begin{cases} x + y = 35 \ 2x + 4y = 94 \end{cases} $$

解得:鸡 23 只,兔 12 只。


三、引葭赴岸

《九章算术》:今有池方一丈,葭生其中央。出水一尺,引葭赴岸,适与岸齐。问水深、葭长各几何。

(1丈 = 10尺)

古代解法:

$$ b = \frac{a^2 - (c - b)^2}{2(c - b)} $$

现代解法:

设水深 $x$ 尺,则葭长 $(x+1)$ 尺:

$$ x^2 + 5^2 = (x + 1)^2 $$

解得:水深 12 尺,葭长 13 尺。


四、最速降线

问题:在重力作用下,一个质点从点 $A$ 滑到点 $B$(不在正下方),沿什么路径所需时间最短?

答案:摆线(Cycloid)。

摆线的参数方程:

$$ \begin{cases} x = r(\theta - \sin\theta) \ y = r(1 - \cos\theta) \end{cases} $$


五、巴塞尔问题

求所有正整数平方倒数的和:

$$ \sum_{n=1}^{\infty} \frac{1}{n^2} = \frac{\pi^2}{6} $$

该问题由欧拉在 1735 年解决,一举成名。


六、费马引理

若函数 $f(x)$ 在 $x_0$ 处可导且取得极值,则 $f’(x_0) = 0$。

这是微分中值定理的基础。


七、素数问题

素数定理: 不超过 $x$ 的素数个数 $\pi(x) \sim \frac{x}{\ln x}$。

费马小定理: 若 $p$ 是质数,且 $a$ 不是 $p$ 的倍数,则:

$$ a^{p-1} \equiv 1 \pmod{p} $$

克拉茨猜想(3n+1 猜想): 任取一正整数,若为偶数则除以 2,若为奇数则乘以 3 再加 1,重复操作,最终总会落入 4→2→1 的循环。至今未被证明。


八、密码学相关问题

密钥管理

  • 如何生成公私钥对?
  • 如何根据编码后的公私钥对得到 PrivateKey、PublicKey?
  • 如何保护密钥的安全?
  • 如何传输交换密钥?

身份认证

如何证明我是我,我妈是我妈?

数字证书及CA

传输层安全性协议(TLS/SSL)是一种安全协议,目的是为互联网通信提供安全及数据完整性保障。


九、算法经典问题

9.1 汉诺塔(Tower of Hanoi)

将 $n$ 个大小不同的圆盘从一根柱子移动到另一根柱子,要求每次只移动一个圆盘,且大盘不能压在小盘上。

最少移动次数: $2^n - 1$

#![allow(unused)]
fn main() {
fn hanoi(n: u32, from: &str, to: &str, aux: &str) {
    if n == 0 { return; }
    hanoi(n - 1, from, aux, to);
    println!("移动圆盘 {} 从 {} 到 {}", n, from, to);
    hanoi(n - 1, aux, to, from);
}
}

9.2 斐波那契数列

$$F(n) = F(n-1) + F(n-2), \quad F(0)=0, ; F(1)=1$$

数列:0, 1, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89, …

斐波那契数列与黄金分割比 $\varphi = \frac{1+\sqrt{5}}{2} \approx 1.618$ 密切相关:$\lim_{n\to\infty} \frac{F(n+1)}{F(n)} = \varphi$。

#![allow(unused)]
fn main() {
fn fibonacci(n: u64) -> u64 {
    let (mut a, mut b) = (0u64, 1u64);
    for _ in 0..n {
        let tmp = a + b;
        a = b;
        b = tmp;
    }
    a
}
}

9.3 背包问题(Knapsack Problem)

给定 $n$ 件物品,每件有重量 $w_i$ 和价值 $v_i$,背包容量为 $W$,求装入背包的最大总价值。

0-1 背包(动态规划):

#![allow(unused)]
fn main() {
fn knapsack_01(weights: &[usize], values: &[usize], capacity: usize) -> usize {
    let n = weights.len();
    let mut dp = vec![0usize; capacity + 1];
    for i in 0..n {
        for w in (weights[i]..=capacity).rev() {
            dp[w] = dp[w].max(dp[w - weights[i]] + values[i]);
        }
    }
    dp[capacity]
}
}

9.4 最长公共子序列(LCS)

给定两个序列,求它们的最长公共子序列的长度。

#![allow(unused)]
fn main() {
fn lcs_length(a: &[char], b: &[char]) -> usize {
    let (m, n) = (a.len(), b.len());
    let mut dp = vec![vec![0usize; n + 1]; m + 1];
    for i in 1..=m {
        for j in 1..=n {
            dp[i][j] = if a[i-1] == b[j-1] {
                dp[i-1][j-1] + 1
            } else {
                dp[i-1][j].max(dp[i][j-1])
            };
        }
    }
    dp[m][n]
}
}

9.5 旅行商问题(TSP)

给定 $n$ 个城市和它们之间的距离,求一条经过所有城市恰好一次并回到起点的最短回路。

TSP 是经典的 NP-hard 问题。暴力求解时间复杂度为 $O(n!)$,动态规划(Held-Karp 算法)可优化至 $O(n^2 \cdot 2^n)$。

9.6 八皇后问题

在 $8 \times 8$ 的国际象棋棋盘上放置 8 个皇后,使得任意两个皇后都不能互相攻击(不同行、不同列、不同对角线)。共有 92 种解法。

#![allow(unused)]
fn main() {
fn solve_n_queens(n: usize) -> Vec<Vec<usize>> {
    let mut solutions = Vec::new();
    let mut cols = vec![0usize; n];
    backtrack(0, n, &mut cols, &mut solutions);
    solutions
}

fn backtrack(row: usize, n: usize, cols: &mut Vec<usize>, solutions: &mut Vec<Vec<usize>>) {
    if row == n {
        solutions.push(cols.clone());
        return;
    }
    for col in 0..n {
        if is_safe(row, col, cols) {
            cols[row] = col;
            backtrack(row + 1, n, cols, solutions);
        }
    }
}

fn is_safe(row: usize, col: usize, cols: &[usize]) -> bool {
    for i in 0..row {
        if cols[i] == col
            || (cols[i] as isize - col as isize).abs() == (row as isize - i as isize)
        {
            return false;
        }
    }
    true
}
}

十、数据结构经典问题

10.1 约瑟夫环(Josephus Problem)

$n$ 个人围成一圈,从第 1 人开始报数,每报到 $m$ 的人出局,求最后幸存者的编号。

递推公式:

$$J(1) = 0, \quad J(n) = (J(n-1) + m) \bmod n$$

#![allow(unused)]
fn main() {
fn josephus(n: usize, m: usize) -> usize {
    let mut pos = 0usize;
    for i in 2..=n {
        pos = (pos + m) % i;
    }
    pos
}
}

10.2 表达式求值与逆波兰表示法

将中缀表达式 3 + 4 * 2 转换为后缀表达式(逆波兰表示法)3 4 2 * +,可用栈高效求值。

#![allow(unused)]
fn main() {
fn eval_rpn(tokens: &[&str]) -> f64 {
    let mut stack: Vec<f64> = Vec::new();
    for &token in tokens {
        match token {
            "+" | "-" | "*" | "/" => {
                let b = stack.pop().unwrap();
                let a = stack.pop().unwrap();
                let result = match token {
                    "+" => a + b,
                    "-" => a - b,
                    "*" => a * b,
                    "/" => a / b,
                    _ => unreachable!(),
                };
                stack.push(result);
            }
            _ => stack.push(token.parse().unwrap()),
        }
    }
    stack.pop().unwrap()
}
}

10.3 图的遍历:BFS 与 DFS

方法数据结构特点典型应用
BFS(广度优先)队列逐层扩展,找最短路径无权最短路径、连通分量
DFS(深度优先)栈/递归深入探索,回溯拓扑排序、环检测、迷宫
#![allow(unused)]
fn main() {
use std::collections::VecDeque;

fn bfs(adj: &[Vec<usize>], start: usize) -> Vec<usize> {
    let n = adj.len();
    let mut visited = vec![false; n];
    let mut order = Vec::new();
    let mut queue = VecDeque::new();
    visited[start] = true;
    queue.push_back(start);
    while let Some(u) = queue.pop_front() {
        order.push(u);
        for &v in &adj[u] {
            if !visited[v] {
                visited[v] = true;
                queue.push_back(v);
            }
        }
    }
    order
}
}

十一、计算理论与复杂度经典问题

11.1 P vs NP 问题

P:能在多项式时间内求解的问题。

NP:能在多项式时间内验证解的问题。

核心问题:$P = NP$ 是否成立?这是计算机科学最重要的未解之谜,也是克雷数学研究所七大千禧年难题之一(悬赏 100 万美元)。

类别示例
P排序、最短路径、最大流
NP旅行商、背包、布尔可满足性(SAT)
NP-complete3-SAT、图着色、子集和
NP-hard停机问题(不可判定)、TSP 优化版

11.2 停机问题(Halting Problem)

1936 年,图灵证明:不存在一个通用算法,能判定任意程序在任意输入上是否会停机。

这是计算理论的核心结论,证明了计算的固有局限性。

11.3 复杂度类全景

复杂度类含义
P多项式时间可解
NP多项式时间可验证
co-NPNP 问题的补集
PSPACE多项式空间可解
EXPTIME指数时间可解
BPP有界错误概率多项式时间

十二、操作系统与网络经典问题

12.1 哲学家就餐问题

5 位哲学家围坐圆桌,每人左右各有一根筷子。哲学家交替思考和进餐,进餐需同时拿到左右两根筷子。如何设计算法避免死锁?

策略说明
资源分级给筷子编号,每人先拿小编号再拿大编号
仲裁者设一个服务员控制筷子的分配
限制人数最多允许 4 人同时拿筷子

12.2 生产者-消费者问题

生产者向缓冲区写入数据,消费者从缓冲区读取数据。需要用信号量或条件变量同步,避免缓冲区溢出或下溢。

#![allow(unused)]
fn main() {
use std::sync::{Arc, Mutex, Condvar};
use std::collections::VecDeque;

struct Buffer<T> {
    queue: Mutex<VecDeque<T>>,
    capacity: usize,
    not_full: Condvar,
    not_empty: Condvar,
}

impl<T> Buffer<T> {
    fn new(capacity: usize) -> Self {
        Buffer {
            queue: Mutex::new(VecDeque::with_capacity(capacity)),
            capacity,
            not_full: Condvar::new(),
            not_empty: Condvar::new(),
        }
    }

    fn produce(&self, item: T) {
        let mut queue = self.queue.lock().unwrap();
        while queue.len() >= self.capacity {
            queue = self.not_full.wait(queue).unwrap();
        }
        queue.push_back(item);
        self.not_empty.notify_one();
    }

    fn consume(&self) -> T {
        let mut queue = self.queue.lock().unwrap();
        while queue.is_empty() {
            queue = self.not_empty.wait(queue).unwrap();
        }
        let item = queue.pop_front().unwrap();
        self.not_full.notify_one();
        item
    }
}
}

12.3 拜占庭将军问题

在分布式系统中,部分节点可能故障或恶意作恶。如何在存在叛徒的情况下达成共识?

结论: 若系统有 $f$ 个故障节点,至少需要 $3f + 1$ 个节点才能达成共识(即容忍 $f$ 个叛徒需要总共 $n \geq 3f+1$ 个节点)。

这是区块链共识算法(PoW、PoS、BFT)的理论基础。


十三、人工智能与博弈经典问题

13.1 图灵测试

1950 年,图灵在论文《计算机器与智能》中提出:如果一台机器能在对话中让人类无法分辨对方是人还是机器,则可以认为该机器具有智能。

13.2 蒙特霍尔问题(三门问题)

参赛者面对三扇门,其中一扇后有汽车,两扇后是山羊。参赛者选择一扇后,主持人打开另一扇有山羊的门,问:是否换门?

答案:换门。 换门后中奖概率从 $\frac{1}{3}$ 提升到 $\frac{2}{3}$。

$$P(\text{换门赢}) = \frac{2}{3}, \quad P(\text{不换赢}) = \frac{1}{3}$$

13.3 极小化极大(Minimax)与井字棋

Minimax 是博弈搜索的核心算法:假设对手采取最优策略,选择使自己收益最大化的行动。

对于井字棋(Tic-Tac-Toe),完整博弈树仅有约 255,168 个节点,可以完全搜索得出最优策略——双方均最优时必然平局。


十四、经典问题索引

算法与数据结构

问题类别难度说明
斐波那契数列递归/动态规划简单递推关系与黄金分割
汉诺塔递归简单经典递归分治,最少 $2^n-1$ 步
背包问题动态规划中等0-1 背包、完全背包、多重背包
最长公共子序列动态规划中等序列比对的基础算法
最长递增子序列动态规划中等$O(n\log n)$ 二分优化
编辑距离动态规划中等字符串相似度度量
旅行商问题组合优化困难NP-hard,Held-Karp 算法 $O(n^2 2^n)$
八皇后问题回溯中等约束满足问题,92 种解
约瑟夫环数学/递推简单$O(n)$ 递推公式
区间调度贪心简单按结束时间排序的贪心选择
Dijkstra 最短路径图论中等单源最短路径,$O((V+E)\log V)$
最小生成树图论中等Kruskal 或 Prim 算法
拓扑排序图论中等DAG 的线性排序
字符串匹配(KMP)字符串中等$O(n+m)$ 模式匹配
快速傅里叶变换数值计算困难$O(n\log n)$ 多项式乘法
并查集数据结构简单近乎 $O(1)$ 的集合合并与查询

计算理论与数学

问题类别说明
P vs NP复杂度理论千禧年七大难题之一,悬赏百万美元
停机问题可计算性图灵 1936 年证明,计算存在固有极限
哥德尔不完备定理数理逻辑任何足够强的公理系统都存在无法证明的真命题
四色定理图论/组合任何地图只需 4 种颜色即可着色(1976 年计算机辅助证明)
费马大定理数论$x^n+y^n=z^n$ 在 $n\geq3$ 时无正整数解(1995 年证明)
黎曼猜想数论素数分布与 ζ 函数零点的关系,悬赏百万美元
生日悖论概率论23 人中两人同天生日的概率超过 50%
蒙提霍尔问题概率论换门概率从 1/3 提升到 2/3

系统与工程

问题类别说明
哲学家就餐并发/死锁Dijkstra 提出的经典同步问题
生产者-消费者并发/同步缓冲区同步的经典模型
拜占庭将军问题分布式系统容错共识的理论基础
两军问题网络通信不可靠信道上无法达成确定共识
CAP 定理分布式系统一致性、可用性、分区容错性三者最多取其二
FLP 不可能定理分布式系统异步系统中无法同时保证终止性和一致性
缓存失效计算机科学“计算机科学只有两个难题:缓存失效和命名”
千年虫问题软件工程两位年份表示导致的全球性软件危机

十五、学习资源

向量知识库