汉诺塔【模拟】

题目大意:

在正常的汉诺塔规则中再加一条:不允许直接把盘从1号柱移动到3号柱,也不允许直接把盘从3号柱移动到1号柱。初始状态为第0步,编程求在某步数时的状态。


思路:

如果把汉诺塔的变化打出来,那么就是这样的:

  1. (1,1,1)
  2. (2,1,1)
  3. (3,1,1)
  4. (3,2,1)
  5. (2,2,1)
  6. (1,2,1)
  7. (1,3,1)
  8. (2,3,1)
  9. (3,3,1)
  10. (3,3,2)
  11. (2,3,2)
  12. (1,3,2)
  13. (1,2,2)
  14. (2,2,2)
  15. (3,2,2)
  16. (3,1,2)
  17. (2,1,2)
  18. (1,1,2)
  19. (1,1,3)
  20. (2,1,3)
  21. (3,1,3)
  22. (3,2,3)
  23. (2,2,3)
  24. (1,2,3)
  25. (1,3,3)
  26. (2,3,3)
  27. (3,3,3)

然后,就能发现:
1号圆盘在移动3次中,共移动了2次;2号圆盘在移动9次中,共移动了2次;3号圆盘在移动27次中,共移动了2次。
那么也就很容易推出:n号圆盘每移动3n次中,会移动两次!
那么这道题就很好做了,预处理3n,每次可以利用周期问题求出答案。
时间复杂度:O(tn),最坏950000


代码:

#include <cstdio>
#include <iostream>
#include <cstring>
using namespace std;

const char o[]={'1','2','3','2'};
int t,n,m,num[31],k;

int main()
{
    scanf("%d",&t);
    num[0]=1;
    for (int i=1;i<=19;i++)
     num[i]=num[i-1]*3;  //预处理
    while (t--)  //t组数据
    {
        scanf("%d%d",&n,&m);
        if (!m)   //特判,没有移动
        {
            for (int i=1;i<n;i++) {putchar('1');putchar(' ');}
            putchar('1');  //全部输出1
            putchar(10);
            continue;
        }
        for (int i=1;i<=n;i++)
        {
            k=(m/num[i]*2)+((m%num[i])/num[i-1]);  //找规律
            putchar(o[k%4]);  //周期
            if (i!=n) putchar(' ');
        } 
        putchar(10);
    }
    return 0;
}
原文地址:https://www.cnblogs.com/hello-tomorrow/p/11998881.html