題意:
漢諾塔游戲請看 百度百科
正常的漢諾塔游戲是只有3個柱子,並且如果有n個圓盤,至少需要2^n-1步才能達到目標。
但是在這題中,有4根柱子,並且按照下面規則來玩:
1. 先把圓盤頂部前k個盤子全部搬到第四根柱子上,
2. 然後把剩下的n-k個盤子在前3根柱子中按照經典的規則搬到某個柱子上(假設是a柱),
3. 最後再把那k個盤子搬到目標a柱上。
問按照這樣的規則,最少需要幾步?
思路:
我們先設g[n]表示按照經典的游戲規則(3根柱子),n個盤子最少需要g[n]步,可以知道g[n] = 2^n-1
然後我們再設f[n]表示按照4根柱子的規則來,n個盤子最少需要f[n]步。
那麼按照上面步驟可以推出:
1. 把圓盤頂部前k個盤子全部搬到第四根柱子 上 ==》 需要f[k]步
2. 把剩下的n-k個盤子在前3根柱子中按照經典的規則搬到某個柱子上 (假設是a柱) ==》需要g[n-k]步
3. 最後再把那k個盤子搬到目標a柱上 ==》需要f[k]步
所以,f[n] = f[k]*2+g[n-k]
因為f[n]要最小,且k不確定,所以枚舉一下k,取最小值即可:
f[n] = min{ f[k]*2+g[n-k] , 1<=k<=n }
由於n過大,所以要用到大數。
由於本題的n為10000,上面的算法復雜度為O(n^2),所以不能用上面方法。
那麼就打表找規律一下,並不難找
觀察下面前20個,不難找出規律:
f[1] = 1 ---------------- f[2] = 3, f[2] = f[1] + 2^1 f[3] = 5, f[3] = f[2] + 2^1 共 2 個 2^1 ---------------- f[4] = 9, f[4] = f[3] + 2^2 f[5] = 13, f[5] = f[4] + 2^2 f[6] = 17, f[6] = f[5] + 2^2 共 3 個 2^2 ---------------- f[7] = 25, f[7] = f[6] + 2^3 f[8] = 33, f[8] = f[7] + 2^3 f[9] = 41, f[9] = f[8] + 2^3 f[10] = 49, f[10] = f[9] + 2^3 共 4 個 2^3 ---------------- f[11] = 65, f[11] = f[10] + 2^4 f[12] = 81, f[12] = f[11] + 2^4 f[13] = 97, f[13] = f[12] + 2^4 f[14] = 113, f[14] = f[13] + 2^4 f[15] = 129, f[15] = f[14] + 2^4 共 5 個 2^4 ---------------- f[16] = 161, f[16] = f[15] + 2^5 f[17] = 193, f[17] = f[16] + 2^5 f[18] = 225, f[18] = f[17] + 2^5 f[19] = 257, f[19] = f[18] + 2^5 f[20] = 289, f[20] = f[19] + 2^5 共 6 個 2^5 ----------------
/**=========================================== * This is a solution for ACM/ICPC problem. * * @author: shuangde * @blog: http://blog.csdn.net/shuangde800 * @email: [email protected] *============================================*/ import java.math.*; import java.util.Scanner; public class Main { public static void main(String args[]){ BigInteger f[] = new BigInteger[10010]; f[0] = BigInteger.valueOf(0); f[1] = BigInteger.valueOf(1); int i = 2; int k=1; while(i <= 10000){ BigInteger add = BigInteger.valueOf(1).shiftLeft(k); for(int j=0; j<k+1 && i<=10000; ++j){ f[i] = f[i-1].add(add); ++i; } ++k; } Scanner cin = new Scanner(System.in); while(cin.hasNext()){ int n = cin.nextInt(); System.out.println(f[n]); } } }