题解 | #循环汉诺塔#
循环汉诺塔
https://www.nowcoder.com/practice/cdf0808f841748faba058c8ef538c731
A(abc)
C B
如上图,以n等于3为例,a、b、c表示依次增大的金片。若想将abc移到B,则需要先将c移动到B(c最大挪完就不用管了,所以优先处理),那么需要ab不压着c且不占用·B,即ab需要从A移动到C才行,然后c再从A移动到B,接着ab再从C移动到B。
可以得到关系式 f(n):1 = f(n - 1):2 + 1 + f(n - 1):2 = 2 * f(n - 1):2 + 1
(其中 f(n):1 表示n层的汉诺塔移动1单位所需的步数, f(n):2 表示n层的汉诺塔移动2单位所需的步数。
同理,f(n):2 = f(n - 1):2 + 1 + f(n - 1):1 + 1 + f(n - 1):2 = 2 * f(n - 1):2 + f(n - 1):1 + 2
而边界值 f(1):1 = 1,f(1):2 = 2,所以可以写出如下代码。
#include <iostream> #include <vector> int main() { int n; std::cin >> n; std::vector<unsigned[2]> dp(n); dp[0][0] = 1; dp[0][1] = 2; for (int i = 1; i < n; ++i) { dp[i][0] = (dp[i - 1][1] * 2 + 1) % 1000000007u; dp[i][1] = (dp[i - 1][1] * 2 + dp[i - 1][0] + 2) % 1000000007u; } std::cout << dp[n - 1][0] << ' ' << dp[n - 1][1]; }
优化一下内存占用得到如下代码。
#include <iostream> int main() { int n; std::cin >> n; unsigned dp0 = 1, dp1 = 2; for (int i = 1; i < n; ++i) { unsigned tmp = (dp1 << 1) + 1; dp1 = (tmp + dp0 + 1) % 1000000007u; dp0 = tmp % 1000000007u; } std::cout << dp0 << ' ' << dp1; }