算法导论5.3习题
- 5.3-1 Marceau 教授不同意引理5.5证明中使用的循环不变式。他对第一次迭代之前循环不变式是否为空提出质疑。他的理由是,我们可以很容易宣称一个空数组不包含0排列。因此一个空的子数组包含一个0排列的概率应是0,从而第一次迭代之前循环不变式无效。请重写过程RANDOMIZE-IN-PLACE,使得相关循环不变式适用于第一次迭代之前的非空子数组,并为你的过程修改引理5.5的证明。
- 5.3-2 Kelp教授决定写一个过程来随机产生除恒等排列(identity permutation)外的任意排列。他提出了如下过程:
- 5.3-3 假设我们不将元素A[i]与子数组A[i..n]中的一个随机元素交换,而是将它与数组任何位置上的随机元素交换:
- 5.3-4 Armstrong教授建议用下面的过程来产生一个均匀随机排列:
- 5.3-5 证明:在过程PERMUTE-BY-SORTING的数组P中,所有元素都唯一的概率至少是 1 − 1 / n 1-1/n 1−1/n。
- 5.3-6 请解释如何实现算法PERMUTE-BY-SORTING,以处理两个或更多优先级相同的情形。也就是说,即使有两个或更多优先级相同,你的算法也应该产生一个均匀随机排列。
- 5.3-7 假设我们希望创建集合 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}的一个随机样本,即一个具有m个元素的集合S, 其中 0 ≤ m ≤ n 0 \leq m\leq n 0≤m≤n,使得每个 m m m集合能够等可能地创建。一种方法是对 i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n设 A [ i ] = i A[i]=i A[i]=i,调用RANDOM-IN-PLACE(A),然后取最前面的 m m m个数组元素。这种方法会对RANDOM过程调用 n n n次。如果 n n n比 m m m大很多,我们能够创建一个随机样本,只对RANDOM调用更少的次数。请说明下面的递归过程返回 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}的一个随机 m m m子集 S S S,其中每个 m m m子集是等可能的,然而只对RANDOM调用 m m m次。
5.3-1 Marceau 教授不同意引理5.5证明中使用的循环不变式。他对第一次迭代之前循环不变式是否为空提出质疑。他的理由是,我们可以很容易宣称一个空数组不包含0排列。因此一个空的子数组包含一个0排列的概率应是0,从而第一次迭代之前循环不变式无效。请重写过程RANDOMIZE-IN-PLACE,使得相关循环不变式适用于第一次迭代之前的非空子数组,并为你的过程修改引理5.5的证明。
伪代码:
RANDOMIZE-IN-PLACE(A)
n = A.length
Swap A[1] with A[RANDOM(1,n)]
for i =1 to n-1
Swap A[i+1] with A[RANDOM(i+1,n)]
证明:
我们使用下面的循环不变式:
在第 i i i次迭代以前,对每个可能的 i i i排列,子数组包含这个 i i i排列的概率是 ( n − i ) ! / n ! (n-i)!/n! (n−i)!/n!
初始化:
第1次迭代之前,对每个可能的1排列,子数组A[1]包含这个1排列的概率是 1 / n 1/n 1/n,即 ( n − 1 ) ! / n ! (n-1)!/n! (n−1)!/n!,在第1次循环迭代以前循环不变式成立。
保持:
我们假设在第 i i i次迭代之前,每种可能的 i i i排列出现在子数组 A [ 1.. i ] A[1..i] A[1..i]中的概率是 ( n − i ) ! / n ! (n-i)!/n! (n−i)!/n!.
我们来检查第 i i i次迭代。考虑一个特殊的 ( i + 1 ) (i+1) (i+1)排列,并以 < x 1 , x 2 , . . . , x i , x i + 1 > <x_1,x_2,...,x_i,x_{i+1}> <x1,x2,...,xi,xi+1>来表示其中的元素。这个排列中包含一个 i i i排列 < x 1 , x 2 , . . . , x i > <x_1,x_2,...,x_i> <x1,x2,...,xi>,后面接着算法在 A [ i + 1 ] A[i+1] A[i+1]里放置 x i + 1 x_{i+1} xi+1.
设E1表示前 i i i次迭代已经在 A [ 1.. i ] A[1..i] A[1..i]中构造了特殊 i i i排列的事件。根据循环不变式, P r { E 1 } = ( n − i ) ! / n ! Pr\{E_1\}=(n-i)!/n! Pr{E1}=(n−i)!/n!. 设 E 2 E_2 E2表示第i次迭代在位置 A [ i + 1 ] A[i+1] A[i+1]放置 x i + 1 x_{i+1} xi+1的事件。当 E 1 E_1 E1和 E 2 E_2 E2都发生时, ( i + 1 ) (i+1) (i+1)排列 < x 1 , x 2 , . . . , x i , x i + 1 > <x_1,x_2,...,x_i,x_{i+1}> <x1,x2,...,xi,xi+1>出现在 A [ 1.. i + 1 ] A[1..i+1] A[1..i+1]中,因此我们希望计算 P r { E 1 ∩ E 2 } Pr\{E1\cap{E2}\} Pr{E1∩E2}.
P r { E 1 ∩ E 2 } = P r { E 2 ∣ E 1 } P r { E 1 } = 1 / ( n − i ) ∗ ( n − i ) ! / n ! = ( n − i − 1 ) ! / n ! Pr\{E1\cap{E2}\} = Pr\{E_2|E_1\}Pr\{E_1\}=1/(n-i)*(n-i)!/n!=(n-i-1)!/n! Pr{E1∩E2}=Pr{E2∣E1}Pr{E1}=1/(n−i)∗(n−i)!/n!=(n−i−1)!/n!
终止:
终止时, i = n i=n i=n,子数组 A [ 1.. n ] A[1..n] A[1..n]是一个给定n排列的概率为 ( n − n ) ! / n ! = 1 / n ! (n-n)!/n!=1/n! (n−n)!/n!=1/n!
因此,RANDOMIZE-IN-PLACE产生一个均匀随机排列。
5.3-2 Kelp教授决定写一个过程来随机产生除恒等排列(identity permutation)外的任意排列。他提出了如下过程:
PERMUTE-WITHOUT-IDENTITY(A)
n = A.length
for i = 1 to n-1
swap A[i] with A[RANDOM(i+1,n)]
这段代码实现了Kelp教授的意图吗?
答:没有。
这里的恒等排列我理解为原数组本身的排列。数组 A [ 1.. n ] A[1..n] A[1..n]的元素能产生的排列数为 n ! n! n!,去除恒等排列后,排列的数为 n ! − 1 n!-1 n!−1.
循环第1次执行后, A [ 1 ] A[1] A[1]可能有的排列有 ( n − 1 ) (n-1) (n−1)种
循环第2次执行后, A [ 1..2 ] A[1..2] A[1..2]可能有的排列有 ( n − 1 ) ( n − 2 ) (n-1)(n-2) (n−1)(n−2)种
循环第3次执行后, A [ 1..3 ] A[1..3] A[1..3]可能有的排列有 ( n − 1 ) ( n − 2 ) ( n − 3 ) (n-1)(n-2)(n-3) (n−1)(n−2)(n−3)种
.
.
.
循环第n次执行后, A [ 1.. n ] A[1..n] A[1..n]可能有的排列有 ( n − 1 ) ∗ ( n − 2 ) ∗ ( n − 3 ) . . . ∗ 2 ∗ 1 (n-1)*(n-2)*(n-3)...*2*1 (n−1)∗(n−2)∗(n−3)...∗2∗1种,即 ( n − 1 ) ! (n-1)! (n−1)!
( n − 1 ) ! (n-1)! (n−1)!不等于 n ! − 1 n!-1 n!−1所以Kelp教授的意图没有实现。
5.3-3 假设我们不将元素A[i]与子数组A[i…n]中的一个随机元素交换,而是将它与数组任何位置上的随机元素交换:
PERMUTE-WITH-ALL(A)
n = A.length
for i = 1 to n
swap A[i] with A[RANDOM(1,n)]
这段代码会产生一个均匀随机排列吗?为什么会或为什么不会?
答:会。
即证明如下循环不变式:在for循环的第i次迭代以前,对每个可能的 ( i − 1 ) (i-1) (i−1)排列,子数组 A [ 1.. i − 1 ] A[1..i-1] A[1..i−1]包含这个 ( i − 1 ) (i-1) (i−1)排列的概率是 ( n − i + 1 ) ! / n ! (n-i+1)!/n! (n−i+1)!/n!。
初始化:第1次迭代之前,此时i=1,由循环不变式可知,对每个可能的0排列,子数组 A [ 1..0 ] A[1..0] A[1..0]包含这个0排列的概率是 ( n − i + 1 ) ! / n ! = n ! / n ! = 1 (n-i+1)!/n!=n!/n!=1 (n−i+1)!/n!=n!/n!=1。子数组A[1…0]是一个空的子数组,并且0排列也没有元素。因而, A [ 1..0 ] A[1..0] A[1..0]包含任何0排列的概率是1,在第1次循环迭代以前循环不变式成立。
保持:我们假设在第i次迭代之前,每种可能的 ( i − 1 ) (i-1) (i−1)排列出现在子数组 A [ 1.. i − 1 ] A[1..i-1] A[1..i−1]中的概率是 ( n − i + 1 ) ! / n ! (n-i+1)!/n! (n−i+1)!/n!,我们要说明在第i次迭代以后,每种可能的 i i i排列出现在子数组 A [ 1.. i ] A[1..i] A[1..i]中的概率是 ( n − i ) ! / n ! (n-i)!/n! (n−i)!/n!。下一次迭代i累加后,还将保持这个循环不变式。
我们来检查第 i i i次迭代。考虑一个特殊的i排列,并以 < x 1 , x 2 , . . . , x i > <x_1,x_2,...,x_i> <x1,x2,...,xi>来表示其中的元素。这个排列中包含一个 ( i − 1 ) (i-1) (i−1)排列 < x 1 , x 2 , . . . , x i − 1 > <x_1,x_2,...,x_{i-1}> <x1,x2,...,xi−1>,后面算法接着在 A [ i ] A[i] A[i]中放置的值 x i x_i xi。设 E 1 E_1 E1表示前 ( i − 1 ) (i-1) (i−1)排列已经在 A [ 1.. i − 1 ] A[1..i-1] A[1..i−1]中构造了特殊 ( i − 1 ) (i-1) (i−1)排列的事件。根据循环不变式, P r { E 1 } = ( n − i + 1 ) ! / n ! Pr\{E_1\}=(n-i+1)!/n! Pr{E1}=(n−i+1)!/n!。设 E 2 E_2 E2表示第 i i i次迭代在位置 A [ i ] A[i] A[i]放置 x i x_i xi的事件。当 E 1 E_1 E1和 E 2 E_2 E2恰好都发生时, i i i排列 < x i , x 2 , . . . , x i > <x_i,x_2,...,x_i> <xi,x2,...,xi>出现在 A [ 1.. i ] A[1..i] A[1..i]中,因此我们希望计算 P r { E 1 ∩ E 2 } Pr\{E_1\cap{E_2}\} Pr{E1∩E2}。
P r { E 1 ∩ E 2 } = P r { E 2 ∣ E 1 } P r { E 1 } Pr\{E_1\cap{E_2}\}=Pr\{E_2|E_1\}Pr\{E_1\} Pr{E1∩E2}=Pr{E2∣E1}Pr{E1}
由于选择第 i i i个元素时选择任何一个元素都是等可能的,并不会受到前 ( i − 1 ) (i-1) (i−1)次选择的影响。因此 E 1 E1 E1和 E 2 E2 E2是相互独立事件。
所以, P r { E 1 ∩ E 2 } = P r { E 1 } P r { E 2 } Pr\{E_1\cap{E_2}\}=Pr\{E_1\}Pr\{E_2\} Pr{E1∩E2}=Pr{E1}Pr{E2}
设放置第 i i i个元素时没有选到 < x 1 , x 2 , . . . , x i − 1 > <x_1,x_2,...,x_{i-1}> <x1,x2,...,xi−1>中的元素为事件A,设选到 x i x_i xi为事件B.由于,
P r { A } = ( n − i + 1 ) / n Pr\{A\}=(n-i+1)/n Pr{A}=(n−i+1)/n
P r { B } = 1 / n Pr\{B\}=1/n Pr{B}=1/n
P r { A ∩ B } = 1 / n Pr\{A\cap{B}\}=1/n Pr{A∩B}=1/n
所以, P r { B ∣ A } = P r { A ∩ B } / P r { A } = 1 / ( n − i + 1 ) Pr\{B|A\}=Pr\{A\cap{B}\}/Pr\{A\}=1/(n-i+1) Pr{B∣A}=Pr{A∩B}/Pr{A}=1/(n−i+1)
所以, P r { E 2 } = P r { B ∣ A } = 1 / ( n − i + 1 ) Pr\{E_2\} = Pr\{B|A\}=1/(n-i+1) Pr{E2}=Pr{B∣A}=1/(n−i+1)
所以, P r { E 1 ∩ E 2 } = P r { E 1 } P r { E 2 } = ( 1 / ( n − i + 1 ) ) ∗ ( ( n − i + 1 ) ! / n ! ) = ( n − i ) ! / n ! Pr\{E_1\cap{E_2}\}=Pr\{E_1\}Pr\{E_2\}=(1/(n-i+1))*((n-i+1)!/n!)=(n-i)!/n! Pr{E1∩E2}=Pr{E1}Pr{E2}=(1/(n−i+1))∗((n−i+1)!/n!)=(n−i)!/n!
终止: 终止时, i = ( n + 1 ) i=(n+1) i=(n+1),子数组 A [ 1.. n ] A[1..n] A[1..n]是一个给定 n n n排列的概率为 ( n − ( n + 1 ) + 1 ) / n ! = 1 / n ! (n-(n+1)+1)/n!=1/n! (n−(n+1)+1)/n!=1/n!
因此,这段代码产生一个均匀随机排列
5.3-4 Armstrong教授建议用下面的过程来产生一个均匀随机排列:
PERMUTE-BY-CYCLIC(A)
n = A.length
let B[1..n] be a new array
offset = RANDOM(1,n)
for i = 1 to n
dest = i + offset
if dest > n
dest = dest -n
B[dest] = A[i]
return B
请说明每个元素
A
[
i
]
A[i]
A[i]出现在
B
B
B中任何特定位置的概率是
1
/
n
1/n
1/n。然后通过说明排列结果不是均匀随机排列,表明
A
r
m
s
t
r
o
n
g
Armstrong
Armstrong教授错了。
答:
A [ i ] A[i] A[i]出现在 B B B中的位置是由 o f f s e t offset offset决定的, o f f s e t offset offset取值范围 { 1 , 2 , . . . , n } \{1,2,...,n\} {1,2,...,n},每个取值的概率都是 1 / n 1/n 1/n, 所以 A [ i ] A[i] A[i]能出现在 B B B中任何特定位置,并且出现在任何位置的概率是 1 / n 1/n 1/n。
按照 A r m s t r o n g Armstrong Armstrong教授的算法,可能的排列结果数量为 n n n. 对于一个 n n n个元素的数组,均匀随机排列的结果应该有 n ! n! n!个。
5.3-5 证明:在过程PERMUTE-BY-SORTING的数组P中,所有元素都唯一的概率至少是 1 − 1 / n 1-1/n 1−1/n。
5.3-6 请解释如何实现算法PERMUTE-BY-SORTING,以处理两个或更多优先级相同的情形。也就是说,即使有两个或更多优先级相同,你的算法也应该产生一个均匀随机排列。
5.3-7 假设我们希望创建集合 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}的一个随机样本,即一个具有m个元素的集合S, 其中 0 ≤ m ≤ n 0 \leq m\leq n 0≤m≤n,使得每个 m m m集合能够等可能地创建。一种方法是对 i = 1 , 2 , . . . , n i=1,2,...,n i=1,2,...,n设 A [ i ] = i A[i]=i A[i]=i,调用RANDOM-IN-PLACE(A),然后取最前面的 m m m个数组元素。这种方法会对RANDOM过程调用 n n n次。如果 n n n比 m m m大很多,我们能够创建一个随机样本,只对RANDOM调用更少的次数。请说明下面的递归过程返回 { 1 , 2 , 3 , . . . , n } \{1,2,3,...,n\} {1,2,3,...,n}的一个随机 m m m子集 S S S,其中每个 m m m子集是等可能的,然而只对RANDOM调用 m m m次。
RANDOM-SAMPLE(m,n)
if m == 0
return Ø
else S = RANDOM-SAMPLE(m-1, n-1)
i = RANDOM(1,n)
if i ∈ S
S = S ∪ {n}
else
S = S ∪ {i}
return S
答:
倒数第1次递归,RANDOM-SAMPLE(0,n-m),返回的空集
倒数第2次递归,RANDOM-SAMPLE(1,n-m+1), 随机数成器为RANDOM(1,n-m+1),返回的集合包含1个元素,特定子集 { x 1 } \{x_1\} {x1}的概率为 1 / ( n − m + 1 ) 1/(n-m+1) 1/(n−m+1)
倒数第3次递归, RANDOM-SAMPLE(2,n-m+2),随机数生成器为RANDOM(1, n-m+2), 返回的集合包含2个元素。假设返回的集合为 { x 1 , x 2 } \{x_1,x_2\} {x1,x2},其中 x 1 < x 2 x_1 <x_2 x1<x2。对 x 2 x_2 x2有两种可能性,一种是 x 2 = n − m + 2 x_2=n-m+2 x2=n−m+2,另一种是 x 2 ∈ ( 1 , n − m + 1 ) x_2 \in (1, n-m+1) x2∈(1,n−m+1)。
x 2 = n − m + 2 x_2=n-m+2 x2=n−m+2时,随机数生成器生成的数为 x 1 x_1 x1或 n − m + 2 n-m+2 n−m+2。设倒数第2次递归返回集合 { x 1 } \{x_1 \} {x1}为事件A,本次递归随机数生成器生成数 x 1 x_1 x1或 n − m + 2 n-m+2 n−m+2为事件B。显然 P { A } = 1 / ( n − m + 1 ) , P { B } = 2 / ( n − m + 2 ) P\{A\}=1/(n-m+1),P\{B\}=2/(n-m+2) P{A}=1/(n−m+1),P{B}=2/(n−m+2)。所以此时 { x 1 , x 2 } \{x_1,x_2\} {x1,x2}的概率为 P { A } ∗ P { B } = 2 / ( n − m + 1 ) ( n − m + 2 ) P\{A\}*P\{B\}=2/(n-m+1)(n-m+2) P{A}∗P{B}=2/(n−m+1)(n−m+2)。
x 2 ∈ ( 1 , n − m + 1 ) x_2 \in (1, n-m+1) x2∈(1,n−m+1)时,倒数第2次递归可能返回的集合为 { x 1 } \{x_1\} {x1}或 { x 2 } \{x_2\} {x2}。设事件 A 1 A_1 A1为倒数第2次递归返回子集 { x 1 } \{x_1\} {x1},事件 A 2 A_2 A2为第2次递归返回子集 { x 2 } \{x_2\} {x2},事件 B 1 B_1 B1为本次递归随机到数 x 2 x_2 x2,事件 B 2 B_2 B2为本次递归随机到数 x 1 x_1 x1,显然 P { A 1 } = P { A 2 } = 1 / ( n − m + 1 ) P\{A_1\}=P\{A_2\}=1/(n-m+1) P{A1}=P{A2}=1/(n−m+1), P { B 1 } = P { B 2 } = 1 / ( n − m + 2 ) P\{B_1\}=P\{B_2\}=1/(n-m+2) P{B1}=P{B2}=1/(n−m+2)。所以此时 { x 1 , x 2 } \{x_1,x_2\} {x1,x2}的概率为 P { A 1 } ∗ P { B 1 } + P\{A_1\}*P\{B_1\}+ P{A1}∗P{B1}+P{A_2}*P{B_2}=2/(n-m+1)(n-m+2) 。 所 以 , 倒 数 第 3 次 递 归 时 , 返 回 特 定 子 集 。 所以,倒数第3次递归时,返回特定子集 。所以,倒数第3次递归时,返回特定子集{x_1,x_2} 的 概 率 为 2 / ( n − m + 1 ) ( n − m + 2 ) 的概率为2/(n-m+1)(n-m+2) 的概率为2/(n−m+1)(n−m+2)
…
倒数第i次递归,RANDOM-SAMPLE(i-1,n-m+i-1),随机数生成器为RANDOM(1, n-m+i-1),返回的集合包含i-1个元素。假设返回特定集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi−1},其中 x 1 < x 2 < . . . < x i − 1 x_1<x_2<...<x_{i-1} x1<x2<...<xi−1。
设倒数第i-1次递归返回特定集合 { x 1 , x 2 , . . . , x i − 2 } \{x_1,x_2,...,x_{i-2}\} {x1,x2,...,xi−2}的概率为p
对于 x i − 1 x_{i-1} xi−1有两种可能性,一种是 x i − 1 = n − m + i − 1 x_{i-1}=n-m+i-1 xi−1=n−m+i−1,另一种是 x i − 1 ∈ ( 1 , n − m + i − 2 ) x_{i-1} \in(1, n-m+i-2) xi−1∈(1,n−m+i−2)。
x i − 1 = n − m + i − 1 x_{i-1}=n-m+i-1 xi−1=n−m+i−1时,随机数生成器生成n-m+i-1或集合 { x 1 , x 2 , . . . , x i − 2 } \{x_1,x_2,...,x_{i-2}\} {x1,x2,...,xi−2}中的一个数,概率为 ( i − 1 ) / ( n − m + i − 1 ) (i-1)/(n-m+i-1) (i−1)/(n−m+i−1)。所以返回特定集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi−1}概率为 p ∗ ( i − 1 ) / ( n − m + i − 1 ) p*(i-1)/(n-m+i-1) p∗(i−1)/(n−m+i−1)
x i − 1 ∈ ( 1 , n − m + i − 2 ) x_{i-1} \in(1, n-m+i-2) xi−1∈(1,n−m+i−2)时,随机数生成器生成集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi−1}中的一个数,概率为 ( i − 1 ) / ( n − m + i − 1 ) (i-1)/(n-m+i-1) (i−1)/(n−m+i−1). 所以返回特定集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi−1}概率为 p ∗ ( i − 1 ) / ( n − m + i − 1 ) p*(i-1)/(n-m+i-1) p∗(i−1)/(n−m+i−1)
…
倒数第m+1次递归,RANDOM-SAMPLE(m,n), 随机数生成器为RANDOM(1, n),返回的集合包含m个元素。所以返回特定集合 { x 1 , x 2 , . . . , x m } \{x_1,x_2,...,x_m\} {x1,x2,...,xm}概率为 p ∗ m / n p*m/n p∗m/n。即 m ! / ( n − m + 1 ) ∗ ( n − m + 2 ) ∗ . . . ∗ n m!/(n-m+1)*(n-m+2)*...*n m!/(n−m+1)∗(n−m+2)∗...∗n,即 1 / C n n − m 1/C_n^{n-m} 1/Cnn−m。