一、概念级:
直接或间接地调用自身的算法称为递归算法。用函数自身给出函数的定义的函数称为递归函数。
例:
阶乘的递归定义
分治的基本原理思想是将一个规模为n的问题分解成为k个规模较小的问题,这些子问题的相互独立且与原问题相同。递归的解这些子问题,然后将各个子问题的解合并到原问题的解。
divide-and-conquer{
if(|P|<=n0) adhoc(P);
divide P into smaller sub-instances P1,P2,P3....Pk
for(int i=0 ; i<=k ; i++){
yi=divide-and-conquer(Pi);
}
return merge(y1,y2,...yk);
}
二、问题集
1.hanoi 问题
设a,b,c为三个塔座,开始时,在塔座a上一共叠有n个大小依次增大的圆盘,各圆盘的编号为1,2,3......n。现要求将塔座a上的所有圆盘移动到塔座b上,并仍按同样的顺序叠置,问移动步骤。
规则:每次只可以移动一个圆盘,任何时候都不允许大圆盘压在小圆盘之上。
代码:
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int step=1;
void hanoi(int n,char a,char b,char c){
if(n>0){
hanoi(n-1,a,c,b);
cout<<step++<<": "<<a<<" -> "<<b<<endl;
hanoi(n-1,c,b,a);
}
}
int main(){
int n;
while( printf("please input the number: ")&&cin>>n){
step=1;
hanoi(n,'A','B','C');
}
return 0;
}
2.二分搜索
给定一组元素,现找到所有元素中的一个特定元素。
#include <iostream>
#include <cstdio>
#include <algorithm>
using namespace std;
int a[100];
template <class type>
int bin_search(type *a,type x,int n){
int l=0,r=n-1;
while(l<=r){
int mid=(l+r)>>1;
if(a[mid]==x) return mid;
else if(a[mid]>x) r=mid-1;
else l=mid+1;
}
return -1;//no this element
}
int main(){
int n;
while(cin>>n){
for(int i=0;i<n;i++)
cin>>a[i];
int ans=bin_search(a,3,n);
if(ans+1)
cout<<"the element at "<<ans+1<<endl;
else cout<<"no this element!"<<endl;
}
return 0;
}
3.大整数的乘法
将n位二进制整数X和Y都分为2部分,每段的长为n/2位(假设n是2 的幂)
假设 X=A2
n/2
+B, Y=C2
n/2
+D;
即有:
XY=(A2
n/2
+B)*(C2
n/2
+D)
=AC2
n
+(AD+BC)2
n/2
+BD
由上式可知,进行一个乘法计算需要4次n/2位的整数乘法(AC,AD,BC,BD),以及2次不超过2n位的整数加法,此外还需要2次移位。假设加法和移位的时间复杂度为O(n)。设T(n)是2 个位数为n的整数相乘所需的运算总数,则有:
由此可知,T(n)=O(n
2
) ,可以看出这和普通的计算方法并无改进。为此我们对计算方法进行了改变:
XY=AC2
n
+((A-B)*(D-C)+AC+BD)2
n/2
+BD
此式看上去更加复杂,但是我们分析一下他的计算过程,可知他由3次的整数乘法和6次的整数加减法,以及2次位移,可得:
容易求得其解为T(n)=O(n
log3
)=O(n
1.59
),可见本次优化是巨大的。
4,棋盘覆盖
在一个2
k
*2
k
个方格组成的棋盘中,若恰有一个方格与其他方格不同,则称该方格为一个特殊方格,且该棋盘为一个特殊棋盘。 在棋盘覆盖问题中,要用图示的4种不同形态的L型骨牌覆盖给定的特殊棋盘上除特殊方格以外的所有方格,且任何2个L型骨牌不得重叠覆盖。
当k>0时,将
2
k
*2
k
棋盘分割为4个2
k-1
×2
k-1
子棋盘(a)所示。特殊方格必位于4个较小子棋盘之一中,其余3个子棋盘中无特殊方格。为了将这3个无特殊方格的子棋盘转化为特殊棋盘,可以用一个L型骨牌覆盖这3个较小棋盘的会合处,如 (b)所示,从而将原问题转化为4个较小规模的棋盘覆盖问题。递归地使用这种分割,直至棋盘简化为棋盘1×1。
实现:每次都对分割后的四个小方块进行判断,判断特殊方格是否在里面。这里的判断的方法是每次先记录下整个大方块的左上角(top left coner)方格的行列坐标,然后再与特殊方格坐标进行比较,就可以知道特殊方格是否在该块中。如果特殊方块在里面,这直接递归下去求即可,如果不在,这根据分割的四个方块的不同位置,把右下角、左下角、右上角或者左上角的方格标记为特殊方块,然后继续递归。在递归函数里,还要有一个变量s来记录边的方格数,每次对方块进行划分时,边的方格数都会减半,这个变量是为了方便判断特殊方格的位置。其次还要有一个变nCount来记录L型骨牌的数量。
代码:
#include <iostream>
#include <algorithm>
#include <cstring>
#include <cstdio>
using namespace std;
int matrix[100][100];
int ncount=1;
void chessboard(int tr,int tc,int dr,int dc,int size) //tr:棋盘左上角的行号列号,dr:特殊方格的行号列号
{
if(size==1) return ;
size/=2;
int t=ncount++;
if(tr+size>dr&&tc+size>dc) chessboard(tr,tc,dr,dc,size);
else{
matrix[tr+size-1][tc+size-1]=t;
chessboard(tr,tc,tr+size-1,tc+size-1,size);
}
if(tr+size>dr&&tc+size<=dc) chessboard(tr,tc+size,dr,dc,size);
else{
matrix[tr+size-1][tc+size]=t;
chessboard(tr,tc+size,tr+size-1,tc+size,size);
}
if(tr+size<=dr&&tc+size>dc) chessboard(tr+size,tc,dr,dc,size);
else{
matrix[tr+size][tc+size-1]=t;
chessboard(tr+size,tc,tr+size,tc+size-1,size);
}
if(tr+size<=dr&&tc+size<=dc) chessboard(tr+size,tc+size,dr,dc,size);
else{
matrix[tr+size][tc+size]=t;
chessboard(tr+size,tc+size,tr+size,tc+size,size);
}
}
int main(){
int size,r,c,row,col;
scanf("%d",&size);
scanf("%d%d",&row,&col);
chessboard(0,0,row,col,size);
for(int i=0;i<size;i++){
for(int j=0;j<size;j++)
cout<<matrix[i][j]<<" ";
cout<<endl;
}
return 0;
}
5.快速排序
快速排序步骤:
•找出一个元素作为基准,然后对数组进行分区操作
•使基准左边元素的值都不大于基准值,基准右边的元素值 都不小于基准值
•如此作为基准的元素调整到排序后的正确位置。
•递归快速排序,将其他n-1个元素也调整到排序后的正确位置。
•最后每个元素都是在排序后的正确位置,排序完成。
我在这拿6 1 2 7 9 3 4 5 10 8这个数组描述,算法过程如下图,依次递归不断更新区间并排序。
代码:
#include <iostream>
using namespace std;
template <class type>
int Partition(type *a,int p,int r){
int i=p,j=r+1;
type x=a[p];
while(1){
while(a[--j]>x&&j>p);
while(a[++i]<x&&i<r);
if(i>=j) break;
swap(a[i],a[j]);
}
a[p]=a[j];
a[j]=x;
return j;
}
template <class type>
void Quick_sort(type *a,int p,int r){
if(p<r){
int q=Partition(a,p,r);
Quick_sort(a,p,q-1);
Quick_sort(a,q+1,r);
}
}
int main(){
int a[100],n,l,r;
while(cin>>n){
for(int i=0;i<n;i++) cin>>a[i];
Quick_sort(a,0,n-1);
for(int i=0;i<n;i++) cout<<a[i]<<' ';
cout<<endl;
}
return 0;
}