《算法笔记》递归和分治

理论知识
分治:将原问题分解为若干个规模较小而结构与原问题相同或相似的子问题,分别解决子问题,最后合并子问题的解得到原问题的解
1.分治法分解出的子问题应当是相互独立,没有交叉的;
2.分治法是一种算法思想,既可以通过递归实现,又可以通过非递归实现;
递归:递归一定要有递归结束条件和递归表达式
求斐波那契数列(递归)
#include <iostream>
#include<vector>
#include<string.h>
using namespace std;
int F(int a){
    //递归结束条件
    if(a == 0 || a == 1) return 1;
    //递归表达式
    return F(a -1) +  F(a - 2);
}

int main()
{
    //求斐波那契数列
    int a = 0;
    scanf("%d", &a);
    int ans = F(a);
    cout << ans;
    system("pause");
    return 0;
}
求全排列(分治)
#include <iostream>
#include<string.h>
using namespace std;

const int MAXN = 11;
//P记录当前排列, HashTable记录数字是否被使用过
int n, P[MAXN], hashTable[MAXN] = {false};
void generateP(int idx){
    //递归结束条件,如果下标为n+1,代表已经输出了n个字符,直接输出
   if(idx == n + 1){
        for(int i = 1; i <= n; i ++){
            printf("%d ", P[i]); //输出数组
        }
        cout << endl;
        return;
   }
    //递归表达式
    for(int x = 1; x <= n; x++) {
            //如果当前数字并没有被用过
        if(hashTable[x] == false){
            P[idx] = x;
            hashTable[x] = true;
            generateP(idx + 1); //递归去处理下一位的子问题
            hashTable[x] = false;//当已经解决这个子问题后,会产生回溯,要把当前位的数字换成别的数字
        }
    }
}

int main()
{
    //求全排列
    scanf("%d", &n);
    generateP(1);
    system("pause");
    return 0;
}
八皇后问题(暴力枚举法)
这种方法在求全排列的基础上,进行改动;
首先利用全排列的枚举方法,去找到不在同一行和同一列的所有可能结果,因为你在枚举全排列的同时就保证了列的不同;
对于每找到的一种结果,要去判断每两个元素是否在同一对角线上
#include <iostream>
#include<string.h>
using namespace std;

const int MAXN = 11;
//P记录当前列上皇后所在的行, HashTable记录数字是否被使用过
int n, P[MAXN], hashTable[MAXN] = {false};
int cnt = 0;
void generateP(int idx){
    //递归结束条件,如果下标为n+1,代表已经输出了n个字符,直接输出
   if(idx == n + 1){
        bool flag = true;
        for(int i = 1; i <= n; i ++){
            for(int j = i + 1; j <= n; j++){
                if(abs(j - i) == abs(P[j] - P[i]))  return;//代表在一条对角线上
            }
        }
        if(flag){
            cnt ++;
            for(int i = 0; i < n; i++) printf("%d ", P[i]);
            cout << endl;
        }
        return;
   }
    //递归表达式
    for(int x = 1; x <= n; x++) {
            //如果当前数字并没有被用过
        if(hashTable[x] == false){
            P[idx] = x;
            hashTable[x] = true;
            generateP(idx + 1); //递归去处理下一位的子问题
            hashTable[x] = false;//当已经解决这个子问题后,会产生回溯,要把当前位的数字换成别的数字
        }
    }
}
int main()
{
    //求全排列
    scanf("%d", &n);
    generateP(1);
    cout << cnt ;
    system("pause");
    return 0;
}
八皇后问题(回溯算法)
回溯:递归的过程中如果出现某一情况已经不满足题意,无需再次递归到边界问题时,称为回溯
#include <iostream>
#include<string.h>
using namespace std;

const int MAXN = 11;
//P记录当前列上皇后所在的行, HashTable记录数字是否被使用过
int n, P[MAXN], hashTable[MAXN] = {false};
int cnt = 0;
void generateP(int idx){
    //递归结束条件,如果下标为n+1,那么这个结果一定是合理的
   if(idx == n + 1){
        cnt ++;
        for(int i = 1; i <= n; i ++) {
            printf("%d ", P[i]);
        }
        printf("\n");
        return;
   }
    //递归表达式
    for(int x = 1; x <= n; x++) {
        //如果当前行并没有皇后,则进行检查
        if(hashTable[x] == false){
            bool flag = true;//记录会不会跟之前的皇后冲突
            for(int pre = 1; pre < idx; pre ++){
                if(abs(idx - pre) == abs(x - P[pre])){
                    flag = false;//如果发现当前皇后与前面某一皇后冲突,则break,这种方法叫做回溯
                    break;
                }
            }
            //如果flag为true,代表没有冲突,继续往下递归
            if(flag){
                P[idx] = x;
                hashTable[x] = true;
                generateP(idx + 1); //递归去处理下一位的子问题
                hashTable[x] = false;//当已经解决这个子问题后,会产生回溯,要把当前位的数字换成别的数字
            }
        }
    }
}

int main()
{
    //求全排列
    scanf("%d", &n);
    generateP(1);
    cout << cnt ;
    system("pause");
    return 0;
}
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值