算法导论5.3习题

算法导论5.3习题

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! (ni)!/n!

初始化:

第1次迭代之前,对每个可能的1排列,子数组A[1]包含这个1排列的概率是 1 / n 1/n 1/n,即 ( n − 1 ) ! / n ! (n-1)!/n! (n1)!/n!,在第1次循环迭代以前循环不变式成立。

保持:

我们假设在第 i i i次迭代之前,每种可能的 i i i排列出现在子数组 A [ 1.. i ] A[1..i] A[1..i]中的概率是 ( n − i ) ! / n ! (n-i)!/n! (ni)!/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}=(ni)!/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{E1E2}.

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{E1E2}=Pr{E2E1}Pr{E1}=1/(ni)(ni)!/n!=(ni1)!/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! (nn)!/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) (n1)
循环第2次执行后, A [ 1..2 ] A[1..2] A[1..2]可能有的排列有 ( n − 1 ) ( n − 2 ) (n-1)(n-2) (n1)(n2)
循环第3次执行后, A [ 1..3 ] A[1..3] A[1..3]可能有的排列有 ( n − 1 ) ( n − 2 ) ( n − 3 ) (n-1)(n-2)(n-3) (n1)(n2)(n3)
     .
     .
     .
循环第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 (n1)(n2)(n3)...21种,即 ( n − 1 ) ! (n-1)! (n1)!
( n − 1 ) ! (n-1)! (n1)!不等于 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) (i1)排列,子数组 A [ 1.. i − 1 ] A[1..i-1] A[1..i1]包含这个 ( i − 1 ) (i-1) (i1)排列的概率是 ( n − i + 1 ) ! / n ! (n-i+1)!/n! (ni+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 (ni+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) (i1)排列出现在子数组 A [ 1.. i − 1 ] A[1..i-1] A[1..i1]中的概率是 ( n − i + 1 ) ! / n ! (n-i+1)!/n! (ni+1)!/n!,我们要说明在第i次迭代以后,每种可能的 i i i排列出现在子数组 A [ 1.. i ] A[1..i] A[1..i]中的概率是 ( n − i ) ! / n ! (n-i)!/n! (ni)!/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) (i1)排列 < x 1 , x 2 , . . . , x i − 1 > <x_1,x_2,...,x_{i-1}> <x1,x2,...,xi1>,后面算法接着在 A [ i ] A[i] A[i]中放置的值 x i x_i xi。设 E 1 E_1 E1表示前 ( i − 1 ) (i-1) (i1)排列已经在 A [ 1.. i − 1 ] A[1..i-1] A[1..i1]中构造了特殊 ( i − 1 ) (i-1) (i1)排列的事件。根据循环不变式, P r { E 1 } = ( n − i + 1 ) ! / n ! Pr\{E_1\}=(n-i+1)!/n! Pr{E1}=(ni+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{E1E2}
           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{E1E2}=Pr{E2E1}Pr{E1}
由于选择第 i i i个元素时选择任何一个元素都是等可能的,并不会受到前 ( i − 1 ) (i-1) (i1)次选择的影响。因此 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{E1E2}=Pr{E1}Pr{E2}
设放置第 i i i个元素时没有选到 < x 1 , x 2 , . . . , x i − 1 > <x_1,x_2,...,x_{i-1}> <x1,x2,...,xi1>中的元素为事件A,设选到 x i x_i xi为事件B.由于,
                     P r { A } = ( n − i + 1 ) / n Pr\{A\}=(n-i+1)/n Pr{A}=(ni+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{AB}=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{BA}=Pr{AB}/Pr{A}=1/(ni+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{BA}=1/(ni+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{E1E2}=Pr{E1}Pr{E2}=(1/(ni+1))((ni+1)!/n!)=(ni)!/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 11/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 0mn,使得每个 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/(nm+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=nm+2,另一种是 x 2 ∈ ( 1 , n − m + 1 ) x_2 \in (1, n-m+1) x2(1,nm+1)
x 2 = n − m + 2 x_2=n-m+2 x2=nm+2时,随机数生成器生成的数为 x 1 x_1 x1 n − m + 2 n-m+2 nm+2。设倒数第2次递归返回集合 { x 1 } \{x_1 \} {x1}为事件A,本次递归随机数生成器生成数 x 1 x_1 x1 n − m + 2 n-m+2 nm+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/(nm+1)P{B}=2/(nm+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/(nm+1)(nm+2)
x 2 ∈ ( 1 , n − m + 1 ) x_2 \in (1, n-m+1) x2(1,nm+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/(nm+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/(nm+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/(nm+1)(nm+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,...,xi1},其中 x 1 < x 2 < . . . < x i − 1 x_1<x_2<...<x_{i-1} x1<x2<...<xi1
设倒数第i-1次递归返回特定集合 { x 1 , x 2 , . . . , x i − 2 } \{x_1,x_2,...,x_{i-2}\} {x1,x2,...,xi2}的概率为p
对于 x i − 1 x_{i-1} xi1有两种可能性,一种是 x i − 1 = n − m + i − 1 x_{i-1}=n-m+i-1 xi1=nm+i1,另一种是 x i − 1 ∈ ( 1 , n − m + i − 2 ) x_{i-1} \in(1, n-m+i-2) xi1(1,nm+i2)
x i − 1 = n − m + i − 1 x_{i-1}=n-m+i-1 xi1=nm+i1时,随机数生成器生成n-m+i-1或集合 { x 1 , x 2 , . . . , x i − 2 } \{x_1,x_2,...,x_{i-2}\} {x1,x2,...,xi2}中的一个数,概率为 ( i − 1 ) / ( n − m + i − 1 ) (i-1)/(n-m+i-1) (i1)/(nm+i1)。所以返回特定集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi1}概率为 p ∗ ( i − 1 ) / ( n − m + i − 1 ) p*(i-1)/(n-m+i-1) p(i1)/(nm+i1)
x i − 1 ∈ ( 1 , n − m + i − 2 ) x_{i-1} \in(1, n-m+i-2) xi1(1,nm+i2)时,随机数生成器生成集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi1}中的一个数,概率为 ( i − 1 ) / ( n − m + i − 1 ) (i-1)/(n-m+i-1) (i1)/(nm+i1). 所以返回特定集合 { x 1 , x 2 , . . . , x i − 1 } \{x_1,x_2,...,x_{i-1}\} {x1,x2,...,xi1}概率为 p ∗ ( i − 1 ) / ( n − m + i − 1 ) p*(i-1)/(n-m+i-1) p(i1)/(nm+i1)

倒数第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 pm/n。即 m ! / ( n − m + 1 ) ∗ ( n − m + 2 ) ∗ . . . ∗ n m!/(n-m+1)*(n-m+2)*...*n m!/(nm+1)(nm+2)...n,即 1 / C n n − m 1/C_n^{n-m} 1/Cnnm

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值