CS70 · 讨论课 06a

Hello World 可计算性、代码可达性、字符串计数

CS 70 讨论课 06A。围绕可计算性理论(停机问题的归约、打印 Hello World 的可计算性、代码行可达性的不可判定性)与计数问题(多重集合排列、隔板法、非负与正整数解计数)展开。

知识焦点

先建立概念地图

  • Computability
  • Halting Problem
  • Reduction
  • Undecidability
  • Code Reachability
  • Counting
  • Multinomial Coefficient
  • Stars and Bars

建议顺序

题面 → 提示 → 答案

先完整作答,再按需展开提示;最后才展开官方参考解答并逐步核对证明与计算。

本地来源

可离线完成

题面与解答均由本地一手资料整理:discussion/dis06a.pdf、solutions/discussion/dis06a-sol.pdf

本地一手资料完整提取 · 讨论课

完整题目、提示与答案

本节按本地一手资料完整整理,共 4 道大题。本地官方解答已完整收录并默认折叠;建议先独立完成,再逐题核对推导。

使用说明

  • 所有题面均已本土化,并补足网页离线作答所需的数值、代码、表格与约束。
  • 题目与答案分层展示,展开答案前可先查看提示。
  • 本地来源:discussion/dis06a.pdf、solutions/discussion/dis06a-sol.pdf
1Hello World! — 可计算性判定题目 · 提示 · 答案
官方题面翻译可离线作答官方解答已收录

完整题面

Note 12 判定下列任务是否可计算。若不可计算,请写出归约(reduction)或自指(self-reference)证明;若可计算,请写出程序。

(a) 给定程序 \(P\) 与输入 \(x\),判定 \(P(x)\) 是否会打印出字符串 "Hello World!"。是否存在一个计算机程序能完成这一任务?证明你的结论。

(b) 给定程序 \(P\)、输入 \(x\) 与整数 \(k\),判定 \(P(x)\) 是否会在执行第 \(k\) 行代码之前打印出 "Hello World!"。是否存在一个计算机程序能完成这一任务?证明你的结论。

(c) 给定程序 \(P\)、输入 \(x\) 与整数 \(k\),判定 \(P(x)\) 是否会在执行的前 \(k\) 步之内打印出 "Hello World!"。是否存在一个计算机程序能完成这一任务?证明你的结论。

查看解题提示

(a)(b) 考虑如何将已知的不可判定问题(例如停机问题 \(\text{TestHalt}(P,x)\) 或上一小问的结论)归约到当前任务:构造一个新程序,使其打印行为"编码"了原问题的答案。

(c) 区别"第 \(k\) 行"与"前 \(k\) 步"的本质差异:程序计数器/源代码行号的追踪是否可被通用程序实现?实际的机器指令步数能否被计数?

展开官方参考解答

(a) 不可计算(Uncomputable)。将 \(\text{TestHalt}(P,x)\) 归约到 \(\text{PrintsHW}(P,x)\):

\[\text{TestHalt}(P, x):\] 构造辅助程序 \(P'(x)\):运行 \(P(x)\) 同时屏蔽所有打印语句;最后执行 print("Hello World!")。

\[\text{if PrintsHW}(P', x): \text{ return true else return false}\]

若 \(\text{PrintsHW}\) 存在,则上述构造给出 \(\text{TestHalt}\) 的一个实现,矛盾。故 \(\text{PrintsHW}\) 不存在。

(b) 不可计算(Uncomputable)。将 (a) 的 \(\text{PrintsHW}(P,x)\) 归约到本问的 \(\text{PrintsByK}(P,x,k)\):

\[\text{PrintsHW}(P, x): \text{ for } i \text{ in range(len}(P\text{)): if PrintsByK}(P, x, i\text{): return true; return false}\]

若 \(\text{PrintsByK}\) 存在则 \(\text{PrintsHW}\) 可判定,矛盾。

(c) 可计算(Computable)。直接模拟运行程序直到执行完 \(k\) 步:若期间 \(P\) 打印了 "Hello World!" 返回真,否则返回假。

(b) 不可计算而 (c) 可计算的原因:是否执行过源代码的某一特定行取决于程序逻辑,无法通用判定;而执行的机器指令条数是可以被计数的。

解答来源:solutions/discussion/dis06a-sol.pdf · 1 · confidence: high

题面来源:discussion/dis06a.pdf · 1 · confidence: high

2代码行可达性 — 不可判定性证明题目 · 提示 · 答案
官方题面翻译可离线作答官方解答已收录

完整题面

Note 12 考虑三元组 \((M, x, L)\),其中

  • \(M\) 是一个 Java 程序;

  • \(x\) 是某个输入;

  • \(L\) 是一个整数(表示代码行号)。

问题为:若执行 \(M(x)\),是否会命中第 \(L\) 行?

证明该问题是不可判定的(undecidable)。

图表条件 · 归约结构示意图:外层 Halt(P,x) 调用内层程序 M,M 的第 1 行运行 P(x)、第 2 行 return,外层再调用 Reachable(M,0,2)。

digraph G { rankdir=LR; Halt [label="Halt(P,x)"]; M [label="M(t)\nL1: run P(x)\nL2: return", shape=record]; Reachable [label="Reachable(M,0,2)"]; Halt -> M -> Reachable; }

来源:solutions/discussion/dis06a-sol.pdf · 1

查看解题提示

假设存在过程 \(\text{Reachable}(M, x, L)\) 能判定该问题。尝试把任意程序 \(P\) 在输入 \(x\) 上的停机问题嵌入进来:构造一个只有两行的程序 \(M\),让"第 \(2\) 行是否可达"等价于 "\(P(x)\) 是否停机"。

展开官方参考解答

假设存在过程 \(\text{Reachable}(M, x, L)\) 能判定上述问题。考虑如下用于判定 \(P(x)\) 是否停机的程序:

\[\begin{aligned} \texttt{def Halt}(P, x):\\ \quad \texttt{def M}(t):\\ \quad \quad \texttt{run P(x)} \quad \# \text{line 1 of } M\\ \quad \quad \texttt{return} \quad \quad \# \text{line 2 of } M\\ \quad \texttt{return Reachable}(M, 0, 2) \end{aligned}\]

程序 \(M\) 会到达第 \(2\) 行当且仅当 \(P(x)\) 停机。于是我们实现了一个停机问题的解法——矛盾。故原问题不可判定。

解答来源:solutions/discussion/dis06a-sol.pdf · 1 · confidence: high

题面来源:discussion/dis06a.pdf · 1 · confidence: high

3字符串计数题目 · 提示 · 答案
官方题面翻译可离线作答官方解答已收录

完整题面

Note 10 给定若干字母,可构造出多少个不同的字符串?

(a) \(n\) 个 1 和 \(m\) 个 0?

(b) \(n_1\) 个 A、\(n_2\) 个 B 和 \(n_3\) 个 C?

(c) \(k\) 种不同字母,分别有 \(n_1, n_2, \ldots, n_k\) 个?

查看解题提示

(a) 在 \(n+m\) 个位置中选出 \(n\) 个放置 1(或等价地选出 \(m\) 个放置 0)。

(b)(c) 推广到多重集合的排列:先视为全排列,再对每种重复字母的非法去重因子做除法。

展开官方参考解答

(a) \(\displaystyle \binom{n+m}{n}\)。

(b) \(\displaystyle \frac{(n_1 + n_2 + n_3)!}{n_1! \cdot n_2! \cdot n_3!}\)。

(c) \(\displaystyle \frac{(n_1 + n_2 + \cdots + n_k)!}{n_1! \cdot n_2! \cdots n_k!}\)。

解答来源:solutions/discussion/dis06a-sol.pdf · 1-2 · confidence: high

题面来源:discussion/dis06a.pdf · 1 · confidence: high

4你永远不会独自计数 — 排列与隔板法题目 · 提示 · 答案
官方题面翻译可离线作答官方解答已收录

完整题面

Note 10

(a) LIVERPOOL 的一个字母重排(anagram)是指对其字母的任意重新排序,即由字母 L, I, V, E, R, P, O, O, L 各使用恰好一次组成的任意字符串(不必是英语单词)。例如 IVLERPOOL 与 POLIVOLRE 是 LIVERPOOL 的重排,但 PIVEOLR 与 CHELSEA 不是。

LIVERPOOL 有多少个不同的字母重排?

(b) 方程 \(y_0 + y_1 + \cdots + y_k = n\) 有多少组解,若每个 \(y_i\) 必须是非负整数(non-negative integer)?

(c) 方程 \(y_0 + y_1 + \cdots + y_k = n\) 有多少组解,若每个 \(y_i\) 必须是正整数(positive integer)?

查看解题提示

(a) 9 个字母的全排列会因重复字母 L(2 次)与 O(2 次)各自互换位置产生重复计数,需除以相应的阶乘。

(b)(c) 联想"stars and bars"(隔板法):把 \(n\) 个 1 排成一行,用 \(k\) 个加号划分成 \(k+1\) 段。注意非负与正整数约束下,"空隙"与"隔板"的可选位置数不同。

展开官方参考解答

(a) 在这个 9 字母单词中,L 与 O 各出现 2 次,其余字母各出现 1 次。\(9!\) 因两个 L 的互换多计了 \(2!\) 倍,又因两个 O 的互换多计了 \(2!\) 倍。故不同重排数为

\[\frac{9!}{(2!)^2}.\]

(b) \(\displaystyle \binom{n+k}{k}\)。把它想象成由 \(n\) 个 1 与 \(k\) 个加号组成的序列:\(y_0\) 是第一个加号之前的 1 的个数,\(y_1\) 是第一个与第二个加号之间的 1 的个数,依此类推。由"balls and bins"(stars and bars)方法计得 \(\binom{n+k}{k}\)。

(c) \(\displaystyle \binom{(n-(k+1))+k}{k} = \binom{n-1}{k}\)。对全部 \(k+1\) 个变量各自减 1,并从总和里减去 \(k+1\),即可化为与 (b) 同型的非负整数问题;求得解后再对每个变量加 1,即得到正整数解。

等价地,由 stars and bars 直接推导:正整数约束意味着不能有空组。考察 \(n\) 个星号之间的 \(n-1\) 个"空隙",从中选出 \(k\) 个放置隔板(两个隔板不能占同一空隙,否则会出现空组),得到 \(\binom{n-1}{k}\) 种分组方式。

解答来源:solutions/discussion/dis06a-sol.pdf · 2-3 · confidence: high

题面来源:discussion/dis06a.pdf · 2-3 · confidence: high


一手资料