递归问题

简介: 递归问题

递归能解决什么问题,当一个问题涉及到规模,并且规模变化问题性质不改变并且有问题出口的情况下,我们自然而然的想到递归。

那又怎么实现递归,许多文章里大致总结了递归程序分为两部分,分别为递归边界部分和递归式部分,了解了这两个部分,一个递归程序基本也就完成。

这个部分,更多是循环渐进的应用实例,来帮大家解决问题。


基础


全排列问题:

给出一个n为1到9的整数,试求1~n这n个数的全排列,并按从小到大输出。


分析题意不妨设用数组p来储存这n个数的排列,要排第n个数只要把前n-1个排好,以此类推,明显该问题可以想象成递归问题。

1.那递归边界怎么确定:该问题排n个,明显到排第n+1个的时候就可以结束,递归边界如下:

if(index==n+1)                        //递归边界 
  {
  for(int i=1;i<n+1;i++)
    cout<<p[i];
    cout<<endl;
  return ;  
  }


2.如何确定递归式

确定递归式的时候,不妨就想象现在正在排第x位,这一位有什么要求,只要数字不是前面出现的即可,排好了就排下一个,这时候我们如果用另外一个t数组的标记有哪些数字还没有排,就可以写成:

else{
    for(int i=1;i<n+1;i++)
    {
   if(!t[i])                        //查找未排的
   {
    p[index]=i;t[i]=true;//排这一位
    permutation(index+1);       // 递归排下一位 
    t[i]=false;                //  回溯 
   }


这里需要注意的是如果用了t数组来标志的话一般有回溯要求,可以自己理解为什么要回溯。


最后总程序如下:

#include<iostream>
using namespace std;
const int maxn=11;
int n,p[maxn],t[maxn]={false}; 
 void permutation(int index)
 {  
  if(index==n+1)                        //递归边界 
  {
  for(int i=1;i<n+1;i++)
    cout<<p[i];
    cout<<endl;
  return ;  
  }
  else{
    for(int i=1;i<n+1;i++)
    {
   if(!t[i]) 
   {
    p[index]=i;t[i]=true;
    permutation(index+1);       // 递归式 
    t[i]=false;                //  回溯 
   }  
     }  
  } 
 }
 int main()
 {
  cin>>n;
  permutation(1);
  return 0;
 }

1685011395068.jpg


应用


n皇后问题:会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将n个皇后放在棋盘上(有n * n个方格),使它们谁也不能被吃掉!

实际上,n皇后可以转化为上面全排列的子问题,不如以顺序记录棋子的横坐标,对应排列数字依次就为横坐标的对于的列坐标,每一组排列确定了一组排放棋子位置。

显然递归边界依旧不变,只是在写递归式的时候,要筛选掉不符合n皇后规则的排序,所以这个问题,只是在全排列问题的递归式部分加上约束条件即可,如下:

else{
  for(int i=1;i<n+1;i++)
    {
   if(!t[i])                                       
   {  int a=1;
      for(int j=1;j<index;j++)                //约束条件
      {
        if((index-j)==abs(i-p[j]))
        a=0;
    }
    if(a){
    p[index]=i;t[i]=true;
    queen(index+1);       
    t[i]=false; }            
   }  
     }


下面是结果:

#include<iostream>
#include<algorithm>
using namespace std; 
const int maxn=11;
int n,p[maxn],t[maxn]={false};
void queen(int index)
{
  if(index==n+1)
  {
  for(int i=1;i<n+1;i++)
    cout<<p[i];
    cout<<endl;
  return ;  
  }
  else{
  for(int i=1;i<n+1;i++)
    {
   if(!t[i])                                       
   {  int a=1;
      for(int j=1;j<index;j++)                //判断这个点是否可行 
      {
        if((index-j)==abs(i-p[j]))
        a=0;
    }
    if(a){
    p[index]=i;t[i]=true;
    queen(index+1);       
    t[i]=false; }            
   }  
     }    
  } 
}
int main()
 {
  n=8;
  queen(1);
  return 0;
 }


进阶


上面那个问题其实得到的结果是多个,那如果只要其中结果的一个又如何中途退出?

八皇后问题:

会下国际象棋的人都很清楚:皇后可以在横、竖、斜线上不限步数地吃掉其他棋子。如何将8个皇后放在棋盘上(有8 * 8个方格),使它们谁也不能被吃掉!这就是著名的八皇后问题。

对于某个满足要求的8皇后的摆放方法,定义一个皇后串a与之对应,即a=b1b2…b8,其中bi为相应摆法中第i行皇后所处的列数。已经知道8皇后问题一共有92组解(即92个不同的皇后串)。

给出一个数b,要求输出第b个串。串的比较是这样的:皇后串x置于皇后串y之前,当且仅当将x视为整数时比y小。


这和上面的n皇后问题几乎一致,只是只要其中第几个结果,这就涉及到退出问题,在我写的程序里,除了递归边界和递归式,还加了一个计数退出段。

#include<iostream>
#include<string>
#include<algorithm> 
using namespace std;
int a[9],b[9];
int n; 
int sum=0;
void generate(int index){ 
  if(index==9) {
  sum++;                                     //递归边界 
  if(sum==n){
    for(int i=1;i<9;i++)
    cout<<a[i];
    cout<<endl;
  }
  return ;
  }
  else if(sum==n) {                                //退出条件 
  return;
  }
  else{
  for(int i=1;i<9;i++){
  if(!b[i]) {
    int flag=1;
      for(int j=1;j<index;j++)                //判断这个点是否可行 
      {
        if((index-j)==abs(i-a[j]))
    flag=0;
    }
    if(flag){
    a[index]=i;b[i]=true;
    generate(index+1);       
    b[i]=false; }            
  }
  } 
  } 
}
int main(){
  int num;
  cin>>num;
  for(int i=0;i<num;i++){
  cin>>n;
  for(int j=1;j<9;j++)b[j]=false;sum=0;
  generate(1);
  }
  return 0;
}


结果:

1685011323452.jpg

相关文章
|
19天前
递归
【10月更文挑战第23天】递归。
14 4
|
6月前
|
算法 C语言
c递归
c递归
42 2
|
6月前
|
算法 C#
C#递归详解
C#递归详解
48 0
|
JavaScript 前端开发
什么是递归?
什么是递归?
102 0
|
Java 数据安全/隐私保护 决策智能
字符串全排列(递归)
字符串全排列,递归的应用
146 0
|
算法 索引
第 6 章 递归
简单的说: 递归就是方法自己调用自己,每次调用时传入不同的变量,递归有助于编程者解决复杂的问题,同时可以让代码变得简洁。
67 0
|
存储 Serverless 开发者
递归的理解与实现
递归的理解与实现
递归的理解与实现
|
机器学习/深度学习
简单的了解一下递归
在编程中,递归大家肯定都不陌生了吧,今天我们来总结总结有关于递归的东西。