算法研讨会-含有回溯的递归算法设计探讨

时间:2019-10-07 21:36:19   收藏:0   阅读:67

含有回溯的递归程序设计

目录

回溯

1.1 概念

1.2 基本思路

从一条路往前走,能进则进,不能进则退回到最近的岔路,换一条路再试。

1.3 问题举例

1.3.1 N皇后问题

在N × N的棋盘上放置N个皇后,这些皇后之间不能相互攻击。(合法位置)

技术分享图片

(图片转自博客园,目前未经过作者同意,如有侵权,将立即删除!)

void Put_The_Queen_On_The_NOk_Row_And_The_NOj_column(int k, int n) {//需要摆放n个皇后,当前摆放到了第k行。
    int j;
    if(k > n)//发现可行解
        print(n); //输出可行解
    else {
         for(j = 1;j <= n;j++) {//试探这一行的每一列
            if(Find_The_Valid_Pos(k, j)) {//判断该位置是否合法
                q[k] = j;   //保存位置
                Put_The_Queen_On_The_NOk_Row_And_The_NOj_column(k + 1, n);  //继续试探下一行
            }
        }
    }
}

1.4 算法设计

  1. 清楚递归边界(什么时候停止递归)
  2. 清楚递归函数的功能(参数的功能、返回值的功能)
  3. 回溯算法设计基本思路
    1. 只要当前层还存在合法选项,那么就在保证当前层合法的前提下,进入试探下一层。
    2. 如果当前层已经不存在合法选项,那么就回溯到上一层,并重复判断1./2.。
    3. 如果发现可行解,那么重复判断1./2.。

1.5 PTA编程题

1.5.1 整数分解为若干项之和

将一个正整数N分解成几个正整数相加,可以有多种分解方法,例如7=6+1,7=5+2,7=5+1+1,…。编程求出正整数N的所有整数分解式子。

void Division(int x, int pos, int result){
    static int counter, array[32];
    if(result != N) {
        for (int i = x; result + i - 1 < N; i++) {
            array[pos] = i;
            Division(i, pos + 1, result + i);
        }
    }
    else{
        counter++;
        std::cout << N << '=';
        for (int i = 0; i < pos - 1; i++)
            std::cout << array[i] << '+';
        if (counter % 4 == 0 || array[pos - 1] == N)
            std::cout << array[pos - 1] << std::endl;
        else
            std::cout << array[pos - 1] << ';';
    }
}

1.5.2 输出全排列

/*全局变量*/
int whole_array[32]; // 存储当前的全排列数
int sub[32]; //记录每一个数字是否被用过
int N; //目标值

/*递归函数*/
void Perm (int x){
    static int length = 0; //当前全排列的长度
    if(N <= x - 1){ //判断全排列树的长度是否等于目标值
        for(int i = 1;i <= N;i++) //输出
            printf("%d",whole_array[i]);    
        printf("\n");
    }
    else //只要全排列数的长度小于目标值
        for(int i = 1;i <= N;i++) //由于要输出字典序,每一个位置从1开始试探
            if(sub[i] == 0){ //判断这个数是否被用过
                whole_array[x] = i; //将这个数
                sub[i] = 1; //填入之后将这个数标记为1,即在该全排列数中已经出现
                Perm(x + 1); //到下一个位置继续试探
                sub[i] = 0; //如果发生回溯,那么需要重新将这个数字标记为没有出现过
            }
}

(博客内容为原创,未经允许禁止转载!)

原文:https://www.cnblogs.com/LYT-Dveloper/p/11632176.html

评论(0
© 2014 bubuko.com 版权所有 - 联系我们:wmxa8@hotmail.com
打开技术之扣,分享程序人生!