思路
相信大家已经了解过汉诺塔问题,并知道如何通过递归实现汉诺塔的转移,先上一段关于汉诺塔问题的传统解法代码。
1 #include2 #include 3 #include <string.h> 4 5 using namespace std; 6 7 long long cnt[3][3]; 8 long long tot = 0; 9 10 void mov(int n, char a, char b, char c) 11 { 12 if(n) 13 { 14 mov(n-1,a,c,b); 15 cnt[a-'a'][c-'a']++; 16 tot++; 17 //printf("%d:%c->%c",n,a,c); 18 //printf("\n"); 19 mov(n-1,b,a,c); 20 } 21 } 22 23 int main() 24 { 25 int n; 26 char a,b,c; 27 a = 'a', b = 'b', c = 'c'; 28 cin >> n; 29 mov(n,a,b,c); 30 /* 31 printf("A->B:%lld\n",cnt[0][1]); 32 printf("A->C:%lld\n",cnt[0][2]); 33 printf("B->A:%lld\n",cnt[1][0]); 34 printf("B->C:%lld\n",cnt[1][2]); 35 printf("C->A:%lld\n",cnt[2][0]); 36 printf("C->B:%lld\n",cnt[2][1]); 37 */ 38 printf("%lld %lld %lld %lld %lld %lld ",cnt[0][1],cnt[0][2],cnt[1][0],cnt[1][2],cnt[2][0],cnt[2][1]); 39 printf("SUM:%lld\n",tot); 40 tot = 0; 41 memset(cnt,0,sizeof(cnt)); 42 main(); 43 return 0; 44 }
通过以上代码,我们可以通过递归求出转移步骤,但是对于本题n达到60的情况显然会TLE。
我们可以通过以上程序在20以内找一下规律。
我们用数组a(1~6)表示A->B,A->C,B->A,B->C,C->A,C->B这6种情况的次数,不难发现a[1] = a[4], a[3] = a[6]
而通过讨论n的奇偶,从4开始,发现n为偶数时,a[i][1] = a[i-1][1] * 4 - cnt1, 其中cnt1此时为0,而且每用到一次就会+1,且a[i][5] = a[i][6]*2;
n为奇数时,a[i][6] = 1ll * a[i-1][6]*4 + cnt2, cnt2此时为2,且用过一次就+1,且a[i][2] = a[i][1]*2 + 1;
这样我们就得到了一个转移的规律。然后我们就可以O(n)地去转移并得到最终的a[n][i] i∈(1,6)
CODE
1 #include2 3 using namespace std; 4 5 long long a[100][10]; 6 using LL = long long; 7 8 9 inline void write(__int128 x) 10 { 11 if(x<0) 12 { 13 putchar('-'); 14 x=-x; 15 } 16 if(x>9) 17 write(x/10); 18 putchar(x%10+'0'); 19 } 20 21 int main() 22 { 23 //a[1][7] = {0,0,1,0,0,0,0}; 24 //a[2][7] = {0,1,1,0,1,0,0}; 25 //a[3][7] = {0,1,3,1,1,0,1}; 26 a[1][1] = 0, a[1][2] = 1,a[1][3] = 0, 27 a[1][4] = 0, a[1][5] = 0,a[1][6] = 0; 28 29 a[2][1] = 1, a[2][2] = 1,a[2][3] = 0, 30 a[2][4] = 1, a[2][5] = 0,a[2][6] = 0; 31 32 a[3][1] = 1, a[3][2] = 3,a[3][3] = 1, 33 a[3][4] = 1, a[3][5] = 0,a[3][6] = 1; 34 int n; 35 long long cnt1 = 0; 36 long long cnt2 = 2; 37 scanf("%d",&n); 38 for(int i = 4; i <= n; ++i) { 39 if(!(i % 2)) {///偶数行 40 a[i][1] = 1ll * a[i-1][1] * 4 - cnt1; 41 cnt1++; 42 a[i][2] = 1ll * a[i-1][2]; 43 a[i][6] = 1ll * a[i-1][6]; 44 a[i][3] = 1ll * a[i][6]; 45 a[i][4] = 1ll * a[i][1]; 46 a[i][5] = 1ll * a[i][6]*2; 47 } 48 else { 49 a[i][1] = 1ll * a[i-1][1]; 50 a[i][2] = 1ll * a[i][1]*2 + 1; 51 a[i][6] = 1ll * a[i-1][6]*4 + cnt2; 52 cnt2++; 53 a[i][3] = 1ll * a[i][6]; 54 a[i][4] = 1ll * a[i][1]; 55 a[i][5] = 1ll * a[i-1][5]; 56 } 57 } 58 59 printf("A->B:%lld\n",a[n][1]); 60 printf("A->C:%lld\n",a[n][2]); 61 printf("B->A:%lld\n",a[n][3]); 62 printf("B->C:%lld\n",a[n][4]); 63 printf("C->A:%lld\n",a[n][5]); 64 printf("C->B:%lld\n",a[n][6]); 65 66 LL sum = 1; 67 for(int i = 1; i <= n; ++i) { 68 sum *= 2; 69 } 70 sum--; 71 printf("SUM:%lld\n",sum); 72 73 return 0; 74 }