2025-10-10?

初始化 \(a_1 = 1 \dots a_n=n\)

execute the following code:

for i in range(1,n+1):
	j = random.randint(1,n)
	swap(a[i],a[j])

证明不能等概率得到 \(1\dots n\) 的随机排列


这个题目可以引申很多知识,很有意思。

  1. 怎么简单修改一下这个代码,使得能等概率随机生成 \(1\dots n\) 的排列:

    for i in range(1,n+1):
    	j = random.randint(i,n)
    	swap(a[i],a[j])
    

    为什么?

    首先我们发现上面的代码可以生成 \(n!\) 种序列,因为第一个位置可以选 n 个... 第 n 个位置可以选 1 个。

    考虑如果选的 \(j_1...j_n\)\(j_1'...j_n'\) 生成了相同的序列:找到最靠前的满足 \(j_k \neq j_k'\)\(k\),那么我们发现进行完 \(1...k-1\) 这些 swap 操作之后,两个操作序列得到的结果相同。进行完 swap(a[k],a[j_k])swap(a[k],a[j'_k])\(a_k\) 不会再发生任何变化了,不同就是不同了。

    那么不同的 \(j\) 序列得到的最终结果也会是不同的

  2. 原题咋做。

    考虑有多少种 \(j\) 序列能把 \(a_1..a_n\) 在 swap 之后得到自己。考虑一张图有 \(n\) 个节点,从 i 向 \(j_i\) 连边,得到了一张 \(n\) 个点 \(n\) 条边的有向图。这是一个外向基环树森林。如果它不是由一个个环构成的,那么它一定不能将 \(1..n\) 变成 \(1..n\)

    考虑如果这个基环树森林是一些环构成的。考虑在环上的交换行为。在环长大于 3 的时候,每个元素都不能 “换过去再换回来”,也就是走一条长度为 2 的路径回到最开始的位置,而是一定要走一个长度为环长的路径回到原点。

    注意到每次连边,会让两个元素的移动距离+1,一个是 \(l^2\),一个是 \(2l\),肯定是不能满足的。而 \(l=2\) 时一定是可以满足的。

    此时基环树森林里面只有一元环和二元环,这样的选 \(j\) 的方案是:\(\sum\limits_{k=0}^{n/2} \binom{n}{2k} (2k)!!\)。总方案数 \(n^n\)。此时问题变成了 \(\sum\limits_{k=0}^{n/2} \binom{n}{2k} (2k)!!\neq \dfrac{n^n}{n!}\)

    好像这时候直接用右边不是整数就证毕了。这也引出了更直接的一个做法:

    如果希望题干代码的运行结果是等概率随机排列,需要满足生成的结果数量是 \(n!\) 的倍数,而 \(n^n\) 并不是。做完了。

不知道 jiayuan 能不能看到这篇博客,也不知道 jiayuan 知不知道什么是外向基环树森林。

posted @ 2025-10-11 00:17  没学完四大礼包不改名  阅读(21)  评论(2)    收藏  举报