首先先回顾一下三汉诺塔问题是如何求解的
假设有n个盘子,A,B,C三个柱子,初始所有盘子都在A柱,求将所有盘子都移动到C柱需要使用的最少步骤。假设F(n)是移动n个盘子到C柱需要的最少步骤,我们只需要将n-1个盘子先移动到B柱,再将第n个盘子移动到C柱,最后将n-1个盘子移动到C柱,过程中n-1个盘子就移动了2*F(n-1)次,那么
F
(
n
)
=
F
(
n
−
1
)
∗
2
+
1
=
F
(
n
−
1
)
∗
2
+
2
n
+
1
F(n) = F(n-1)*2 + 1 = F(n-1)*2 + 2^n + 1
F(n)=F(n−1)∗2+1=F(n−1)∗2+2n+1
接下来是四汉诺塔问题,假设有n个盘子,A,B,C,D四个柱子,初始所有盘子都在A柱,求将所有盘子移动到D柱需要使用的最少步骤。假设G(n)是将n个盘子移动到D柱的最少步骤
1.首先 将n-k个盘子移动到B或C柱
2. 然后将k个盘子移动到D柱(这个步骤是三汉诺塔问题)
3. 最后将最开始移动的n-k个盘子移动到D柱
那么
G
(
n
)
=
2
∗
G
(
n
−
k
)
+
F
(
k
)
G(n) = 2*G(n-k) + F(k)
G(n)=2∗G(n−k)+F(k)
题目要求最少的步骤,那么我们需要研究k值的最优选取。
假设0<=i<k,k值为最优的选取,同时将式子变形一下,写成
2
∗
G
(
k
)
+
F
(
n
−
k
)
<
2
∗
G
(
i
)
+
F
(
n
−
i
)
2*G(k) + F(n-k) < 2*G(i) + F(n-i)
2∗G(k)+F(n−k)<2∗G(i)+F(n−i)
当n增大时,恒有F(n-k) < F(n-i),G(k),G(i) 不变,k 始终比 i 更优,因此 k 具有决策单调性,所以当求去最优的k时可以从上一层的最优值k开始枚举。因为最优值k是未知的,所以可以采取枚举的方法取最优值k。
1、题目链接
2、题目描述
数据:
这里给出的n值很大,所以求出来的G(n)也很大,需要使用高精度,所以在这里我是用python来实现,同时通过对数据的观察和验证,可以得出k值选取的规律,就不需要枚举取得了,我也不多说,列出数据慢慢体会
n | 1 | 2 | 3 | 4 | 5 | 6 | … |
---|---|---|---|---|---|---|---|
G(n) | 1 | 3 | 5 | 9 | 13 | 17 | … |
G(n)- G(n-1) | None | 2 | 2 | 4 | 4 | 4 | … |
k | 0 | 1 | 2 | 2 | 2或3 | 3 | … |
lst = [0] # 初始化
difference = 1 # 前后差值
cnt = 0 # 统计个数
limit = 1 # 个数上限
for i in range(1, 10001): # 初始化所有值
lst.append(lst[i-1]+difference)
cnt += 1
if cnt == limit: # 当cnt=limit时,差值乘2,cnt重置为0,limit加1
difference *= 2
cnt = 0
limit += 1
n = eval(input())
for i in range(n):
x = eval(input())
print(lst[x])
其实在做题目最简单的方法就是观察规律,观察前后结果之间的差值,然后模拟就行了(仅限个别题目,大部分题目还是要好好推理),最终我选择实现的方式也是采用观察出来的现象模拟结果,也为了避免手写高精度选择了用python实现。
上面分析了那么多也是为了锻炼思维,在比赛时能条理清晰的分析,而不是无从下手。