【算法设计与分析】递归与分治策略

一 递归

递归算法:直接或者间接调用自身的算法称为递归算法

全排列问题

void Perm(int list[], int k, int m)//前缀[0:k-1],后缀[k,m]
{
      if(k==m)
       {   for(int i=0;i<=m;i++)   cout<<list[i];
            cout<<endl;
        }
      else
         for(int i=k;i<=m;i++)
          {  
              swap(list[k],list[i]);
              Perm(list, k+1,m);
              swap(list[k],list[i]);//恢复现场
          } 
} 
Perm(list,0,n-1);

二 分治

1.该问题的规模缩小到一定的程度就可以容易地解决;
2.该问题可以分解为若干个规模较小的相同问题
3.利用该问题分解出的子问题的解可以合并为该问题的解;
4.该问题所分解出的各个子问题是相互独立的,即子问题之间不包含公共的子问题。
分治策略注意事项:
1子问题与原始问题性质完全一样
2 子问题之间可彼此独立地求解
3. 递归停止时子问题可直接求解。

在这里插入图片描述

棋盘覆盖问题

int title;
void chess(int tr,int tc,int dr,int dc,int size)//tr棋盘左上角,dr特殊方格
{
    if(size==1)
        return;
    int s=size/2;
    int t=title++;//每个L形骨牌三个位置,用同一个数字表示
    //左上角
    if(dr<tr+s&&dc<tc+s)//特殊方格在此棋盘
        chess(tr,tc,dr,dc,s);//递归此小棋盘
    else   //没有特殊方格
    {
        b[tr+s-1][tc+s-1]=t;//将小棋盘中右下角,标记为特殊方格
        chess(tr,tc,tr+s-1,tc+s-1,s);//递归此小棋盘,
        //并将特殊方格dr,dc,用具体标记过的tr+s-1,tc+s-1表示
    }
    //右上角
    if(dr<tr+s&&dc>=tc+s)
        chess(tr,tc+s,dr,dc,s);
    else
    {
        b[tr+s-1][tc+s]=t;
        chess(tr,tc+s,tr+s-1,tc+s,s);
    }
    //左下角
    if(dr>=tr+s&&dc<tc+s)
        chess(tr+s,tc,dr,dc,s);
    else
    {
        b[tr+s][tc+s-1]=t;
        chess(tr+s,tc,tr+s,tc+s-1,s);
    }
     //右下角
    if(dr>=tr+s&&dc>=tc+s)
        chess(tr+s,tc+s,dr,dc,s);
    else
    {
        b[tr+s][tc+s]=t;
        chess(tr+s,tc+s,tr+s,tc+s,s);
    }


}

合并排序

在这里插入图片描述

void copy(int a[],int b[], int left, int right)
{
   for(i=left;i<=right; i++)
   a[i]=b[i];
} 
void MergeSort(int a[], int left, int  right)
   {
         if (left==right)   return;            //程序出口
         int mid=(left+right)/2;                //取中点
         MergeSort(a, left, mid);            //子问题1递归调用
         MergeSort(a, mid+1, right);      //子问题2递归调用
         Merge(a, b, left, mid, right);     //合并子问题的解得到原问题的解,存入数组b
         copy(a, b, left, right);            //复制回数组a
    }
    void Merge(int a[], int b[], int left, int mid, int right)          
{
    i=left;j=mid+1; k=left;
    while(i<=mid&&j<=right)
    if(a[i]<=a[j])  b[k++]=a[i++];
     else b[k++]=b[j++];
     while(i<=mid)    b[k++]=a[i++];
     while(j<=right)   b[k++]=b[j++];
}

归并排序

在这里插入图片描述

void Merge(int a[], int b[], int left, int mid, int right)          
{
    i=left;j=mid+1; k=left;
    while(i<=mid&&j<=right)
    if(a[i]<=a[j])  b[k++]=a[i++];
     else b[k++]=b[j++];
     while(i<=mid)    b[k++]=a[i++];
     while(j<=right)   b[k++]=b[j++];
}
void mergesort(int a[], int n)
{
   int b[100];  int s=1;
   while(s<n)
   { 
      MergePass(a,b,s,n);
      s=2*s;
      MergePass(b,a,s,n);
      s=2*s;
     }
}
void mergepass(int x[], int y[], int s, int n)
{  int  i=0;
//第一段i:i+s-1,第二段i+s:i+2s-1
//每一段都是长度为s
   while(i<=n-2*s)  //i+2*s-1<=n-1,有两段
  {
   Merge(x,y,i,i+s-1,i+2*s-1); //合并,上一个程序里的一样
    i=i+2*s;
   }
   if(i+s<n)       //大于1段,不足2段
     Merge(x,y,i, i+s-1,n-1);
    else           //不大于1段,直接赋值
      for(j=i; j<=n-1; j++)
         y[j]=x[j];
}

快速排序

本质就是把基准数大的都放在基准数的右边,把比基准数小的放在基准数的左边,这样就找到了该数据在数组中的正确位置.

void Quick_Sort(int *arr, int begin, int end){
    if(begin > end)
        return;
    int tmp = arr[begin];
    int i = begin;
    int j = end;
    while(i != j){//相遇就退出
        while(arr[j] >= tmp && j > i)
            j--;
        while(arr[i] <= tmp && j > i)
            i++;
        if(j > i){//走不动交换
            int t = arr[i];
            arr[i] = arr[j];
            arr[j] = t;
        }
    }
    arr[begin] = arr[i];//与基准数交换
    arr[i] = tmp;
    Quick_Sort(arr, begin, i-1);
    Quick_Sort(arr, i+1, end);
}


循环赛日程表

void Table(int k,int **a)
{
int m=1;
for(int s=1;s<=k;s++)
   {
    n/=2;//分组。
     for(int t=1;t<=n;t++)//组
        for(int i=m+1;i<=2*m;i++)//行
             for(int j=m+1;j<=2*m;j++)//列
                {  a[i][j+(t-1)*m*2]=a[i-m][j+(t-1)*m*2-m];//交换元素
                   a[i][j+(t-1)*m*2-m]=a[i-m][j+(t-1)*m*2];
                }
      m*=2; 
     }
 }    
  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值