《程序设计与算法》第二章【递归】

递归的基本概念

递归的基本概念:一个函数调用其自身,就是递归
例:求n!的递归函数

1. int Factorial(int n) {
2.   if (n == 0)
3.       return 1;
4.   return n * Factorial(n-1);
5. }

F(3)2->F(3)4->F(2)2->F(2)4->F(1)2->F(1)4-> F(0)2->F(0)3:返回1->
F(1)4:返回1*1->F(2)4:返回2*1-> F(3)4:返回3*2-> 函数执行结束

递归的作用

  • 替代多重循环
  • 解决本来就是用地鬼形式定义的问题
  • 将问题分解为规模更小的子问题进行求解

N皇后问题(用递归替代多重循环)

题目描述
n皇后问题:输入整数n, 要求n个国际象棋的皇后,摆在 n*n的棋盘上,互相不能攻击,输出全部方案。
输入一个正整数N,则程序输出N皇后问题的全部摆法。
输出结果里的每一行都代表一种摆法。行里的第i个数字如 果是n,就代表第i行的皇后应该放在第n列。
皇后的行、列编号都是从1开始算。

样例输入:
4

样例输出:
2413
3142

解答

#include <iostream>
#include <cmath>
using namespace std;
int N;
int queenPos[100];  // 用来存放算好的皇后的位置,最左上角是(0,0)
void NQueen(int k) {  // 在0~k-1行皇后已经摆好的情况下,摆第k行及其后的皇后
    int i;
    if (k == N) {   // N个皇后已经摆好
        for (i = 0; i < N; i++) {
            cout << queenPos[i] + 1 << " ";
        }
        cout << endl;
        return;
    }
    for (i = 0; i < N; i++) {   // 逐尝试第k个皇后的位置
        int j;
        for (j = 0; j < k; j++) {   // 和已经摆好的k个皇后的位置比较,看是否冲突
            if (queenPos[j] == i || abs(queenPos[j]-i) == abs(k-j)) {
                break;    // 冲突,尝试下一个位置
            }
        }
        if (j == k) {   // 当前选的位置i不冲突
            queenPos[k] = i;  // 将第k歌皇后摆放在位置i
            NQueen(k+1);
        }
    }
}
int main() {
    cin >> N;
    NQueen(0);  // 从第0行开始摆放皇后
    return 0;
}

逆波兰表达式(用递归解决递归形式的问题)

题目描述
逆波兰表达式是一种把运算符前置的算术表达式(其实一般教科书上称这种表 达式为波兰表达式) ,例如普通的表达式2 + 3的逆波兰表示法为+ 2 3。逆波兰 表达式的优点是运算符之间不必有优先级关系,也不必用括号改变运算次序,例如 (2 + 3) * 4的逆波兰表示法为* + 2 3 4。本题求解逆波兰表达式的值,其中运算符 包括+ - * /四个。
输入:
输入为一行,其中运算符和运算数之间都用空格分隔,运算数是浮点数。
输出:
输出为一行,表达式的值。

样例输入:
* + 11.0 12.0 + 24.0 35.0

样例输出:
1357.000000
提示:(11.0+12.0)*(24.0+35.0)

解答

#include <iostream>
#include <cstdio>
#include <cstdlib>
using namespace std;
double exp() {   // 读入一个逆波兰表达式,并计算其值
    char s[20];
    cin >> s;
    switch (s[0]) {
        case '+':
            return exp()+exp();
            break;
        case '-':
            return exp()-exp();
            break;
        case '*':
            return exp()*exp();
            break;
        case '/':
            return exp()/exp();
            break;

        default: return atof(s);
            break;
    }

}
int main() {
    printf("%lf\n", exp());
    return 0;
}

四则运算表达式求值(用递归解决递归形式的问题)

题目描述
输入为四则运算表达式,仅由整数、+、-、*、/ 、(、) 组成,没有空格,要求求其值。假设运算符结果都是整数 。”/”结果也是整数。

解题思路
表达式是个递归的定义:


因此对于表达式可以进行递归分析处理。

解答

#include <iostream>
#include <cstring>
#include <cstdlib>
using namespace std;
int term_value();
int factor_value();
int expression_value();
int main() {
    cout << expression_value() << endl;
    return 0;
}
int expression_value() {         // 求一个表达式的值
    int result = term_value();   // 求第一个项的值
    while (true) {
        char op = cin.peek();    // 看第一个字符,不取走
        if (op == '+' || op == '-') {
            cin.get();           // 从输入中取走一个字符
            int value = term_value();
            if (op == '+')
                result += value;
            else
                result -= value;
        }
        else
            break;

    }
    return result;
}
int factor_value() {             // 求一个因子的值
    int result = 0;
    char c = cin.peek();
    if (c =='(') {
        cin.get();
        result = expression_value();
        cin.get();
    }
    else {
        while(isdigit(c)) {
            result = 10 * result + c - '0';
            cin.get();
            c = cin.peek();
        }
    }
    return result;
}
int term_value() {              // 求一个项的值
    int result = factor_value();
    while (true) {
        char op = cin.peek();
        if (op == '*' || op == '/') {
            cin.get();
            int value = factor_value();
            if (op == '*')
                result *= value;
            else
                result /= value;
        }
        else
            break;
    }
    return result;
}

爬楼梯(用递归将问题分解为规模更小的子问题进行求解)

题目描述
老师爬楼梯,他可以每次走1级或者2级,输入楼梯的级数, 求不同的走法数。
例如:楼梯一共有3级,他可以每次都走一级,或者第一次走一级,第二次走两级,也可以第一次走两级,第二次走一级,一 共3种方法。

输入:
输入包含若干行,每行包含一个正整数N,代表楼梯级数,1 <= N <= 30输出不同的走法数,每一行输入对应一行。
输出:
不同的走法数,每一行输入对应一行输出。

样例输入:
5
8
10

样例输出:
8
34
89

解题思路
n级台阶的走法 = 先走一级后,n-1级台阶的走法 + 先走两级后,n-2级台阶的走法
f(n) = f(n-1)+f(n-2)

边界条件:
n < 0 0
n = 0 1

n = 0 1
n = 1 1

n = 1 1
n = 2 2

解答

#include <iostream>
using namespace std;
int N;
int stairs(int n) {
    if (n < 0)
        return 0;
    if (n == 0)
        return 1;
    return
        stairs(n-1) + stairs(n-2);
}
int main() {
    while (cin >> N) {
        cout << stairs(N) << endl;
    }
    return 0;
}

放苹果

题目描述
把M个同样的苹果放在N个同样的盘子里,允许有的盘子空着不放, 问共有多少种不同的分法?5,1,1和1,5,1 是同一种分法。

输入:
第一行是测试数据的数目t(0 <= t <= 20)。以下每行均包含二个整 数M和N,以空格分开。1<=M,N<=10。
输出:
对输入的每组数据M和N,用一行输出相应的K。

样例输入:
1
73

样例输出:
8

解题思路
设i个苹果放在k个盘子里放法总数是 f(i,k),则:k > i 时,f(i,k) = f(i,i)
k <= i 时,总放法 = 有盘子为空的放法+没盘子为空的放法,f(i,k) = f(i,k-1) + f(i-k,k)

解答

#include <iostream>
using namespace std;
int f(int m, int n) {
    if (n > m)     // 盘子大于苹果
        return f(m, m);
    if (m == 0)    // 没有苹果
        return 1;
    if (n <= 0)    // 没有盘子
        return 0;
    return f(m, n-1) + f(m-n, n);   // 有盘子为空加没盘子没空
}
int main() {
    int t, m, n;
    cin >> t;
    while (t--) {
        cin >> m >> n;
        cout << f(m, n) << endl;
    }
    return 0;
}

算24

题目描述
给出4个小于10个正整数,你可以使用加减乘除4种运算以及括号把这4个数连接起来得到一个表达式。现在的问题是,是否存 在一种方式使得得到的表达式的结果等于24。
这里加减乘除以及括号的运算结果和运算的优先级跟我们平常的定义一致(这里的除法定义是实数除法)。
比如,对于5,5,5,1,我们知道5 * (5 – 1 / 5) = 24,因此可以得到24。又比如,对于1,1,4,2,我们怎么都不能得到 24。

输入:
输入数据包括多行,每行给出一组测试数据,包括4个小于10个正整 数。最后一组测试数据中包括4个0,表示输入的结束,这组数据不用处理。
输出:
对于每一组测试数据,输出一行,如果可以得到24,输出“YES”; 否则,输出“NO”。

样例输入:
5 5 5 1
1 1 4 2
0 0 0 0

样例输出:
YES
NO

解题思路
n个数算24,必有两个数要先算。这两个数算的结果,和剩余n-2个数,就构成了n-1个数求24的问题。枚举先算的两个数,以及这两个数的运算方式。
注意:浮点数比较是否相等,不能用 ==

解答

#include <iostream>
#include <cmath>
using namespace std;
double a[5];
#define EPS 1e-6
bool isZero(double x) {
    return fabs(x) <= EPS;
}
bool count24(double a[], int n) {  // 用数组a里的n个数,计算24
    if (n == 1) {
        if(isZero(a[0] - 24))
            return true;
        else
            return false;
    }
    double b[5];
    for (int i = 0; i < n-1; i++) {
        for (int j = i + 1; j < n; j++) {   // 枚举两个数的组合
            int m = 0;   // 还剩下m个数, m = n - 2
            for (int k = 0; k < n; k++)
                if (k != i && k != j)
                    b[m++] = a[k];  // 把其余数放入b
            b[m] = a[i] + a[j];
            if (count24(b, m+1))
                return true;
            b[m] = a[i] - a[j];
            if (count24(b, m+1))
                return true;
            b[m] = a[j] - a[i];
            if (count24(b, m+1))
                return true;
            b[m] = a[i] * a[j];
            if (count24(b, m+1))
                return true;
            if (!isZero(a[j])) {
                b[m] = a[i] / a[j];
                if (count24(b, m+1))
                    return true;
            }
            if (!isZero(a[i])) {
                b[m] = a[j] / a[i];
                if (count24(b, m+1))
                    return true;
            }
        }
    }
    return false;
}
int main() {
    while(true) {
        for (int i = 0; i < 4; i++) {
            cin >> a[i];
        }
        if (isZero(a[0]))
            break;
        if(count24(a, 4))
            cout << "YES" << endl;
        else
            cout << "NO" << endl;
    }
    return 0;
}

猜你喜欢

转载自blog.csdn.net/beashaper_/article/details/80517751