[基础算法]递推与递归

1. 递归实现指数型枚举 AcWing92


从1 ~ n 这 n (n < 20) 个整数中随机选取任意多个,输出所有可能的选择方案。

相当于每个数字有0(不选)、1(选)两种状态,共2^n种情况。

vector<int> chosen;
void calc(int x) {
    if (x == n + 1) {
        for (int i = 0; i < chosen.size(); i++)
            printf("%d", chosen[i]);
        puts("");
        return;
    }
    //不选,则进入子问题
    calc(x + 1);
    
    //选,压入数组,然后进入子问题
    chosen.push_back(x);
    calc(x + 1);
    
    //准备回溯到上一问题执勤啊,还原现场(将这一层问题上压入的元素取出)
    chosen.pop_back();
}
int main() {
    calc(1);
}

2. 递归实现组合型枚举 AcWing93


从1 ~ n 这 n 个整数中随机选取m(0 ≤ m ≤ n < 20)个,输出所有可能的选择方案。

在第一题的基础上,进行剪枝(大于和小于m的不要)。

vector<int> chosen;
void calc(int x) {
		//添加的内容:剪去已选择的数已经大于m的、已选择的数加上x和剩下的数也不足m的
		//1 2 3 4 5
		if(chosen.size() > m || chosen.size() + (n - x + 1) < m){
			return;
		}
		
    if (x == n + 1) {
        for (int i = 0; i < chosen.size(); i++)
            printf("%d", chosen[i]);
        puts("");
        return;
    }
    //不选,则进入子问题
    calc(x + 1);
    
    //选,压入数组,然后进入子问题
    chosen.push_back(x);
    calc(x + 1);
    
    //准备回溯到上一问题执勤啊,还原现场(将这一层问题上压入的元素取出)
    chosen.pop_back();
}
int main() {
    calc(1);
}

3. 递归实现排列型枚举 AcWing94


把1 ~ n 这 n (n < 10) 个整数排成一行后随机打乱顺序,输出所有可能的次序。

int order[20]; //存输出序列
bool chosen[20]; //查看该数字是否用过
//和上个问题不同,这里的x表示的不是数,而是数组中的位置;i表示的才是数
void calc(int x){
	if(x == n + 1){
		for(int i = 1; i <= n; i++){
			printf("%d ", order[i]);
		}
		puts("");
		return;
	}
	
	for(int i = 1; i <= n; i++){
		if(chosen[i]) //子问题跳过父问题中已选过的数
			continue;
		order[x] = i; //这样通过一次for循环,遍历x位置为1~n所有数的情况
		chosen[i] = 1;
		calc(x + 1); //子问题,及其他数的放置
		chosen[i] = 0; //还原现场
		//order[x] = 0; 可以不要这句,因为数组可以直接覆盖
	}
}
int main() {
    calc(1);
}

4. 费解的开关 AcWing95


在一个5*5的01矩阵中,点击任意一个位置,该位置以及它上下左右四个相邻的位置中的数字都会变化(0变1,1变0),问:判断是否可能在6步以内使给定的01矩阵变成全1矩阵,能则输出最小步数,不能则输出-1?

#include <iostream>
#include <algorithm>
#include <cstring>

using namespace std;

const int N = 5;

//改变数组:上下左右中
int dx[5] = {0, 0, -1, 1, 0};
int dy[5] = {-1, 1, 0, 0, 0};

char arr[N][N];
char backup[N][N];

//改变函数
void turn(int x, int y) {
    for (int i = 0; i < 5; i++) { //五个位置
        int fx = x + dx[i];
        int fy = y + dy[i];
        if (fx < 0 || fx > 4 || fy < 0 || fy > 4)
            continue;
        arr[fx][fy] = (arr[fx][fy] == '0') ? '1' : '0';
    }
}

int main() {
    int n;
    cin >> n;
    while (n--) {
        //每行当成字符串录入
        for (int i = 0; i < 5; i++) {
            cin >> arr[i];
        }
        int res = 25; //设置所需步数为最大值

        //更改第一行(枚举:32种)
        for (int op = 0; op < 32; op++) {
            //备份数组,每枚举一种还原一次
            memcpy(backup, arr, sizeof arr);
            //计数器(记录步骤)
            int count = 0;
            for (int i = 0; i < 5; i++) { //第一行的五个位置
                if (op >> i & 0) { //五个位置中哪些位置为0,则变化那些位置(op为二进制,
                    //op遍历0~31十进制数相当于将第一行五个位置遍历00000~11111)
                    count++;
                    turn(0, i);
                }
            }

            //根据第一行更改后四行
            for (int i = 0; i < 4; i++) { //行
                for (int j = 0; j < 5; ++j) { //列
                    if (arr[i][j] == '0') {
                        count++;
                        turn(i + 1, j); //变化下一行的同一位置
                    }
                }
            }

            //检查最后一行是否全为1(前四行此时必定全为1)
            bool flag = false;
            for (int i = 0; i < 5; i++) {
                if (arr[4][i] == '0') {
                    flag = true;
                    break;
                }
            }
            //若通过,更新res
            if (!flag) {
                res = min(res, count);
            }

            //还原现场
            memcpy(arr, backup, sizeof arr);
        }
        if (res > 6)
            res = -1;
        cout << res << endl;
    }
    return 0;
}

5. Strange Towers of Hanoi AcWing96


解出n个盘子3座塔和4座塔的Hanoi(汉诺塔)问题最少需要多少步?

三座塔:设d[n]为n盘三塔问题的最少步骤,则有d[n] = 2 * d[n – 1] + 1

四座塔:设f[n]为n盘四塔问题的最少步骤,则有f[n] = min(1≤i<n){2 * f[i] + d[n – i]}

//三塔
#include <iostream>

using namespace std;

int hanoi(int n) {
    if (n == 1)
        return 1;
    else {
        return 2 * hanoi(n - 1) + 1;
    }
}

int main() {
    int n;
    cin >> n;
    cout << hanoi(n);

    return 0;
}

//四塔
#include <iostream>

using namespace std;

int hanoi3(int n) {
    if (n == 1)
        return 1;
    else {
        return 2 * hanoi3(n - 1) + 1;
    }
}

int hanoi4(int n) {
    if (n == 1)
        return 1;
    else {
        int res = 2 + hanoi3(n - 1);
        for (int i = 2; i < n; i++) {
            res = (res > (2 * hanoi4(i) + hanoi3(n - i))) ? (2 * hanoi4(i) + hanoi3(n - i)) : res;
        }
        return res;
    }
}

int main() {
    for (int i = 1; i <= 12; i++) {
        cout << hanoi4(i) << endl;
    }
    return 0;
}

视频讲解

https://pan.baidu.com/s/1Js1fR1N-XUm_xadjGJZZWQ?pwd=9q5d 提取码: 9q5d

本人邮箱:yhyshiroha123@outlook.jp
暂无评论

发送评论 编辑评论


				
|´・ω・)ノ
ヾ(≧∇≦*)ゝ
(☆ω☆)
(╯‵□′)╯︵┴─┴
 ̄﹃ ̄
(/ω\)
∠( ᐛ 」∠)_
(๑•̀ㅁ•́ฅ)
→_→
୧(๑•̀⌄•́๑)૭
٩(ˊᗜˋ*)و
(ノ°ο°)ノ
(´இ皿இ`)
⌇●﹏●⌇
(ฅ´ω`ฅ)
(╯°A°)╯︵○○○
φ( ̄∇ ̄o)
ヾ(´・ ・`。)ノ"
( ง ᵒ̌皿ᵒ̌)ง⁼³₌₃
(ó﹏ò。)
Σ(っ °Д °;)っ
( ,,´・ω・)ノ"(´っω・`。)
╮(╯▽╰)╭
o(*////▽////*)q
>﹏<
( ๑´•ω•) "(ㆆᴗㆆ)
😂
😀
😅
😊
🙂
🙃
😌
😍
😘
😜
😝
😏
😒
🙄
😳
😡
😔
😫
😱
😭
💩
👻
🙌
🖕
👍
👫
👬
👭
🌚
🌝
🙈
💊
😶
🙏
🍦
🍉
😣
Source: github.com/k4yt3x/flowerhd
颜文字
Emoji
小恐龙
花!
上一篇
下一篇