算法设计与分析——递归与分治问题(含锐格题)

递归的概念:直接或间接调用自身的算法

适合递归算法的问题

1.递归函数:用函数自身给出定义的函数
2.递归结构:二叉树

递归算法设计的一般步骤

1.确定递归关系
2.确定终止条件※
3.确定递归参数

实例

1.汉诺塔问题
#include 
#include
using namespace std;
 int cnt=0;//记录
void move(int id, char from, char to) // 打印移动方式:编号,从哪个盘子移动到哪个盘子
{
    printf ("step %d: move %d from %c->%c\n", ++cnt, id, from, to);
}
void hanoi(int n,char a,char b,char c)
{
    if(n==0)
        return;//终止条件
    else
    {
        hanoi(n-1,a,c,b);//将a柱上的n-1个盘子通过c移动到b上
        move(n,a,c);//将a柱上第n个盘子移动到b上
        hanoi(n-1,b,a,c);//再将b柱上的n-1个盘子通过a移动到c盘上
    }
}

int main()
{
    int n;
    cin>>n;
    hanoi(n,'A','B','C');
    return 0;
}

2.排列问题
#include 
#include
using namespace std;
void Perm(int a[],int k,int m)
{
    if(k==m)//只有一个元素
    {
        for(int i=1;i<=m;i++)
        {
            cout<<a[i];
        }
        cout<<endl;//注意放在括号外面
    }
    else
    {
        for(int i=k;i<=m;i++)
        {
            swap(a[k],a[i]);//先将ak和ai交换,将ai放到最前面,后面的元素全排列
            Perm(a,k+1,m);
            swap(a[k],a[i]);//将ai换回
        }
    }
}
void swap(int a,int b)
{
   int r=a;
    a=b;
    b=r;
}
int main()
{
    int n;
    int a[100];
    cin>>n;
    for(int i=1;i<=n;i++)
        cin>>a[i];
    Perm(a,1,n);
    return 0;
}

递归小结:

优点:结构清晰,可读性强,而且容易用数学归纳法来证明算法的正确性,因此它为设计算法,调试程序带来很大方便
缺点:递归算法的运行效率较低,无论是耗费的计算时间还是占用的存储孔家都比非递归算法要多

分治所解决问题的特征

1、原问题的规模缩小到一定的程度就可以容易地解决
2.原问题可以分解为若干个规模较小的相同子问题
3.合并子问题的解可以得到原问题的解
4.子问题之间互相独立,即不同子问题不包含公共子问题

分治注意事项

1.子问题与原问题性质完全相同
2.子问题之间相互独立,可分别求解
3.最小子问题可直接求解

实例

1.数组元素升序排序

算法设计与分析——递归与分治问题(含锐格题)_第1张图片

#include 

using namespace std;
 int a[100];
//int b[100];
void Merge(int a[],int m,int mid,int n )
{
    int i=m;
    int j=mid+1;
    int k=1;
    int s;
    int b[10]={0};//临时的数组,对a中数组进行排序
    while((i<=mid)&&(j<=n))
    {
        if(a[i]<=a[j])
            b[k++]=a[i++];
        else b[k++]=a[j++];
    }
    while(i<=mid)//注意放在上一个括号外面,将剩下的全部放入b中
    {
        b[k++]=a[i++];
    }
    while(j<=n)
    {
        b[k++]=a[j++];
    }
    k=1;
    for(int i=m;i<=n;i++)
    {
        a[i]=b[k++];//再将排序好的数组放回a中
    }

}
//void Copy(int a[],int b[],int m,int n)
//{
//    for(int i=m,j=1;i<=n;i++,j++)
//        a[i]=b[j];
//}
void Sort(int a[],int m,int n)
{
    if(m<n)//分治
    {
        int mid=(m+n)/2;//分为左右两边分别排序
        Sort(a,m,mid);
        Sort(a,mid+1,n);
        Merge(a,m,mid,n);//合并到数组b中
//        Copy(a,b,m,n);//复制回a
    }
}

int main()
{
    int n;
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    Sort(a,1,n);
    for(int i=1;i<=n;i++)
        cout<<a[i]<<" ";
    return 0;
}


2.求a中元素最大值

算法设计与分析——递归与分治问题(含锐格题)_第2张图片

#include 

using namespace std;
int Maxn(int a[],int m,int n)
{
    int mid=(m+n)/2;
    int max1;
    int max2;
    if(m==n)
        return a[m];
    else
    {
        max1=Maxn(a,m,mid);//找左右两边的最大值
        max2=Maxn(a,mid+1,n);
        if(max1>max2)//选出最大值并返回
            return max1;
        else return max2;
    }
}
int main()
{
    int n;
    int a[100];
    cin>>n;
    for(int i=1;i<=n;i++)
    {
        cin>>a[i];
    }
    cout<<Maxn(a,1,n);
    return 0;
}


3.大整数乘法
4.矩阵乘法
5.棋盘覆盖问题

算法设计与分析——递归与分治问题(含锐格题)_第3张图片

#include 
#include
#include
using namespace std;
int a[100][100];
int tile=1;
void ChessBoard(int tr,int tc,int dr,int dc,int sizea)
{
    if(sizea==1)
        return;//最小规模
    int t=tile++;//全局变量,记录
    int s;
    s=sizea/2;//分割棋盘
    if(dr<tr+s&&dc<tc+s)//特殊方格 左上角
     ChessBoard(tr,tc,dr,dc,s);
    else
    {
        a[tr+s-1][tc+s-1]=t;
        ChessBoard(tr,tc,tr+s-1,tc+s-1,s);
    }
    if(dr<tr+s&&dc>=tc+s)//覆盖右上角
    {
        ChessBoard(tr,tc+s,dr,dc,s);
    }
    else
    {
        a[tr+s-1][tc+s]=t;
        ChessBoard(tr,tc+s,tr+s-1,tc+s,s);
    }
    if(dr>=tr+s&&dc<tc+s)//左下角
    {
        ChessBoard(tr+s,tc,dr,dc,s);
    }
    else
    {
        a[tr+s][tc+s-1]=t;
        ChessBoard(tr+s,tc,tr+s,tc+s-1,s);
    }
    if(dr>=tr+s&&dc>=tc+s)//右下角
    {
        ChessBoard(tr+s,tc+s,dr,dc,s);
    }
    else
    {
        a[tr+s][tc+s]=t;
        ChessBoard(tr+s,tc+s,tr+s,tc+s,s);
    }
}
int main()
{
    int n;
    int ki,kj;
    int k;//2的k次方
    int t;t=1;
    cin>>n>>ki>>kj;
//    for(int i=1;;i++)
//    {
//        t=powf(2,i);
//        if(t<=n)
//            k=i;
//        if(t>n)
//            break;//注意加终止条件
//    }
//    cout<
    ChessBoard(1,1,ki,kj,n);
    for(int i=1;i<=n;i++)
    {
         for(int j=1;j<=n;j++)
          {
              cout.width(2);
              cout<<a[i][j]<<" ";
        }
        cout<<endl;
    }
    return 0;
}


//

你可能感兴趣的:(算法设计与分析,笔记,分治算法,算法,c++)