2020牛客寒假算法基础集训营3-I 牛牛的汉诺塔【规律构造】

 

思路

  相信大家已经了解过汉诺塔问题,并知道如何通过递归实现汉诺塔的转移,先上一段关于汉诺塔问题的传统解法代码。

 

 1 #include <iostream>
 2 #include <stdio.h>
 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 #include <bits/stdc++.h>
 2 
 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 }
View Code

猜你喜欢

转载自www.cnblogs.com/orangeko/p/12285379.html