Hanoi塔问题
请观察上图即可,图片所显示其实就是我们处理hanoi塔的三步。
(注意:图片事网上找来的,汉诺塔问题是从 “A” 借助 “C” 转移到 “B” )
假设f(x) : 把x个盘子 全部从A借助C转移到B时 所用的步数。
以上图举例子。
1、首先先把4个盘子通过B转移到C 操作步数为:f(4)
2、然后把最底层的盘子(编号为5)移动到B 操作步数为:1
3、最后把4个盘子通过A转移到B 操作步数为:f(4)
通过上述例子:
可得到:f(5) = 2*f(4)+1
随着盘子的增多,问题其实仅仅是从底层多加了delta层,但解决的步骤依旧一样。
递归计算

1 #include<iostream> 2 using namespace std; 3 4 int Hanoi(int x){ 5 if( x == 1 ) 6 return 1 ; 7 else 8 return Hanoi(x-1) * 2 + 1 ; 9 } 10 int main() 11 { 12 int n ; 13 cin >> n ; 14 cout << Hanoi(n) << endl ; 15 return 0; 16 }
递归记录路径

1 #include<iostream> 2 using namespace std; 3 //打印其路径 4 void Move( char u , char v ){ 5 printf("%c -> %c\n",u,v); 6 } 7 8 //起点为A , 过程中借助C , 最后到达B 9 //( A -> C -> B ) 10 void Hanoi( int n , char A , char B , char C ){ 11 if( n > 0 ){ 12 Hanoi( n - 1 , A , C , B ); 13 Move( A , B ); 14 Hanoi( n - 1 , C , B , A ); 15 } 16 } 17 int main() 18 { 19 int n ; 20 cin >> n ; 21 Hanoi(n,'A','B','C'); 22 return 0; 23 }
虽然代码非常简短,但是其递归过程比较复杂。
针对每一堆盘子来说,都是分三步,
通过 得知自己所在的位置,借助哪根柱子,最后要移动到哪一个柱子。
但是对于过程中的第一步,其实是递归后的结果。
Hanoi( n - 1 , A , C , B ); =>…… Move( A , B ); Hanoi( n - 1 , C , B , A );
由这句话往下到下一层
Hanoi( n - 1 , A , C , B ) { => …… (***) { Hanoi( n - 3 , A , C , B ) => { { Hanoi( n - 2 , A , B , C ) => { Move ( A , C ) { => { Move ( A , C ) { Hanoi( n - 3 , C , B , A ) { Hanoi( n - 2 , B , A , C )
一直往下递归,直到如上所示的.
"(***)" 作为第一句,然后回溯依次执行。
……
对于递归函数的设计,我们需要做到“整体把握”
但对于具体实现的过程,一定要明确其中的“具体过程”。
如果把该程序比做一棵递归树(三叉树),打印到屏幕的第一句执行的必定是整棵树的最左下角的叶子结点。
对于问题的阐述:(以图作为例子)
f(n) -> f(n-1) + 1 + f(n-1) f(n-1) -> f(n-2) + 1 + f(n-2) …… f(2) -> f(1) + "1" + f(1) f(0) + 1 + f(0) + "1" + f(0) + 1 + f(0) --- 第一个执行的操作
切面条
一根高筋拉面,中间切一刀,可以得到2根面条。
如果先对折1次,中间切一刀,可以得到3根面条。
如果连续对折2次,中间切一刀,可以得到5根面条。
那么,连续对折10次,中间切一刀,会得到多少面条呢?
题目提及到了“对折”一词。 必定是会使面条加倍 f(0) = 2 f(1) = 3 f(2) = 5 f(3) = 9 f(4) = 17 …… 肯定是围绕着幂次进行找规律。 所以答案就是f(n) = 2^n + 1
补充的内容,并不是考点。
快速幂

算法步骤如上所示:
其实仅仅是利用任何数字转变成2进制后,
每一个位置上权值要么为‘1’,要么为‘0’的特点。
我们可以通过基数和指数相互配合,基数 和底数 同时进行左移。
若当前指数所对应的位置是'1'
ans 必须乘以当前底数
若当前指数所对应的位置为'0'
不执行任何操作
若指数所对应的位置越界时则算法结束,当前对应的ans=pow( base , n )

1 #include<iostream> 2 using namespace std; 3 4 //快速幂函数 5 int qpow( int a , int b ){ 6 int ans = 1 ; 7 //把目标次幂b ->转化成2进制. 8 while( b ){ 9 //如果当前是b最末尾为1答案进行累成 10 if( b % 2 == 1 ){ 11 ans = ans * a ; 12 } 13 //基数和次幂同时移位 14 b = b / 2 ; 15 a = a * a ; 16 } 17 //输出答案 18 return ans ; 19 } 20 int main() 21 { 22 int n = 10 , Base = 2; 23 cout << qpow( Base , n ) + 1 << endl ; 24 return 0; 25 }
平面上的直线
【题意】
平面上有 n 条直线,最多可以把整个平面分成多少份?
L(0) = 1
L(1) = 2
L(2) = 4
L(3) = 7
通过观察可以得知:
L(n) = L(n-1) + n
= L(n-2) + n-1 + n
= ……
= 1 + Sn
排列问题
给定 n 个元素,求出这 n 个元素的全排列。

1 //排列问题 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 const int N = 20 ; 6 int a[N] ; 7 void Perm( int S , int E ){ 8 if( S == E ){ 9 for( int i = 1 ; i <= E ; i++ ){ 10 printf("%3d",a[i]); 11 } 12 putchar('\n'); 13 return ; 14 } 15 for( int i = S ; i <= E ; i++ ){ 16 swap( a[S] , a[i] ); 17 Perm( S + 1 , E ); 18 swap( a[S] , a[i] ); 19 } 20 } 21 int main() 22 { 23 int n = 3 ; 24 for( int i = 1 ; i <=n ; i++ ) a[i] = i ; 25 Perm( 1 , n ); 26 return 0 ; 27 }
整数划分问题
【题目描述】
将正整数 n 划分为一系列正整数的和:
6=6 6=5+1 6=4+2=4+1+1 6=3+3=3+2+1=3+1+1+1 6=2+2+2=2+2+1+1=2+1+1+1+1 6=1+1+1+1+1+1+1
共11 种情况
书本P14页有具体的推导过程及解释

1 //整数划分问题 - 公式法 2 #include<cstdio> 3 #include<algorithm> 4 using namespace std; 5 int solve( int n , int m ){ 6 if( ( n < 1 ) || ( m < 1 ) ) 7 return 0 ; 8 else if( ( n==1) || ( m==1) ) 9 return 1 ; 10 else if( n < m ) 11 return solve( n , n ); 12 else if( n == m ) 13 return solve( n , m-1 ) + 1 ; 14 else 15 return solve( n , m - 1 ) + solve( n - m , m ); 16 } 17 int main() 18 { 19 printf("%d\n",solve(6,6)); 20 return 0 ; 21 }
模拟多项式乘法即可。
具体原理:https://blog.csdn.net/Z_sea/article/details/86529635

1 //整数划分-母函数 2 #include<cstdio> 3 using namespace std; 4 const int N = 1e3 + 10 ; 5 int f[N] , tmp[N] ; 6 int main() 7 { 8 int n = 6 ; 9 f[0] = 1 ; 10 for( int i = 1 ; i <= n ; i ++ ){ 11 for( int j = 0 ; j <= n ; j ++ ){ 12 for( int k = i ; k <= n ; k += i ){ 13 tmp[j+k] += f[j] ; 14 } 15 } 16 for( int j = 0 ; j <= n ; j++ ){ 17 f[j] += tmp[j] ; 18 tmp[j] = 0 ; 19 } 20 } 21 printf("%d\n",f[n]); 22 return 0 ; 23 }
二分搜索技术
【题目描述】
给定已排好序的 n 个元素 a[0:n-1],在其中查找一个特定元素 x。

1 #include<cstdio> 2 using namespace std; 3 const int N = 1e3 ; 4 int a[N] = { 1 , 2 , 3 , 6 , 7 , 11 }; 5 int main() 6 { 7 int x ; 8 bool flag = false ; 9 scanf("%d",&x); 10 int L = 0 , R = 6 ; 11 while( L <= R ){ 12 int Mid = ( L + R ) / 2 ; 13 if( a[Mid] == x ){ 14 printf("Index : %d\n",Mid); 15 flag = true ; 16 } 17 18 if( x < a[Mid] ) R = Mid - 1 ; 19 else L = Mid + 1 ; 20 } 21 if( !flag ){ 22 printf("Not Found\n"); 23 } 24 return 0 ; 25 } 26 /* 27 1 28 Index : 0 29 30 10 31 Not Found 32 */
棋盘覆盖
【分析】
分四个部分,如果是特殊点标注的部分,则另外3个部分的顶角位置标注,再进行分治。
最后问题会一直标记,问题规模不断减少,直到为一个格子时则返回。
【具体代码】

1 //棋盘覆盖 2 #include<cstdio> 3 const int N = 8 ; 4 //t(x,y) -> top-left :左上角的坐标 5 //s(x,y) -> special :特殊标识的坐标 6 //L : 讨论当前方格的边长 7 //tag : 时间戳 8 int chessboard[N][N] ; 9 int tag = 1 ; 10 void f( int tx , int ty , int sx , int sy , int L ){ 11 12 if( L == 1 ){ 13 return ; 14 } 15 int t = tag ++ ; 16 int len = L / 2 ; 17 18 //判断特殊点是否在左上部分? 19 if( sx < tx + len && sy < ty + len ){ 20 //继续分治 21 f( tx , ty , sx , sy , len ); 22 }else{ 23 //填上序号,并继续分治 24 chessboard[tx+len-1][ty+len-1] = t ; 25 f( tx , ty , tx+len-1 , ty+len-1 , len ); 26 } 27 28 //判断特殊点是否在右上部分? 29 if( sx < tx + len && ty + len <= sy ){ 30 //继续分治 31 f( tx , ty + len , sx , sy , len ); 32 }else{ 33 //填上序号,并继续分治 34 chessboard[tx+len-1][ty+len] = t ; 35 f( tx , ty + len , tx+len-1, ty+len , len ); 36 } 37 38 //判断特殊点是否在左下部分? 39 if( tx + len <= sx && sy < ty + len ){ 40 //继续分治 41 f( tx + len , ty , sx , sy , len ); 42 }else{ 43 //填上序号,并继续分治 44 chessboard[tx+len][ty+len-1] = t ; 45 f( tx + len , ty , tx+len , ty+len-1 , len ); 46 } 47 48 //判断特殊点是否在右下部分? 49 if( tx + len <= sx && ty + len <= sy ){ 50 //继续分治 51 f( tx + len , ty + len , sx , sy , len ); 52 }else{ 53 //填上序号,并继续分治 54 chessboard[tx+len][ty+len] = t ; 55 f( tx + len , ty + len , tx+len , ty+len , len ); 56 } 57 58 59 } 60 int main() 61 { 62 //棋盘初始左上角,初始特殊点,边长为8 63 f( 0 , 0 , 0 , 1 , 8 ); 64 for( int i = 0 ; i < 8 ; i++ ){ 65 for( int j = 0 ; j < 8 ; j++ ){ 66 printf("%4d",chessboard[i][j]); 67 } 68 putchar('\n'); 69 } 70 return 0 ; 71 }