递归算法实例应用(五)

算24 (POJ 2787)

Description

给出4个小于10的正整数,你可以使用加减乘除4种运算以及括号把这4个数连接起来得到一个表达式。现在的问题是,是否存在一种方式使得得到的表达式的结果等于24。

这里加减乘除以及括号的运算结果和运算的优先级跟我们平常的定义一致(这里的除法定义是实数除法)。

比如,对于5,5,5,1,我们知道5 * (5 – 1 / 5) = 24,因此可以得到24。

又比如,对于1,1,4,2,我们怎么都不能得到24。

Input

输入数据包括多行,每行给出一组测试数据,包括4个小于10的正整数。

最后一组测试数据中包括4个0,表示输入的结束,这组数据不用处理。

Output

对于每一组测试数据,输出一行,如果可以得到24,输出“YES”;否则,输出“NO”。

Sample Input

5 5 5 1
1 1 4 2
0 0 0 0

Sample Output

YES
NO

算法思想:

同样拿到题之后呢,首先第一个想法依旧是能否将问题分解为规模更小的子问题,然后利用递归解决。

对于问题解决的第一步而言,普遍想法是,先找两个数进行一种加、减、乘、除运算,再将该结果与剩下的n-2个数进行运算,那么此时,问题规模就变为了n-1,因此本题就转变为一个递归问题。

再考虑递归的次数,我们从第一步的初始状态开始不断递归判断是否能满足题设要求,当以此为初始条件均不能满足题设要求时,应继续判定下一初始条件,所以我们应枚举所有可能的第一步的初始状态,即:枚举所有可能的两个数的组合。再以此为初始条件进行递归判断是否为解。

其次考虑递归的边界条件,基于前几题的求边界条件思想,本题的边界情况十分明显,即当问题规模递归减少为1时,仅有一个数,判断与24是否相等,若相等则应返回true,表明找到一组解,若不相等应返回false,表明本次递归的初始条件不能满足题设要求。

详细说明关于在递归时数据的处理:

  1. 选出两个数作为初始条件进行加、减、乘、除运算,选取时应取遍所有可能的组合,可通过二重循环实现。
  2. 将这两个数(a和b)的运算结果与余下的n-2个数存起来,共n-1个数,存入一个数组中,作为中间变量,在以该中间变量数组进行递归,依次判断a+b、a-b、b-a、a*b、a/b、b/a六种情况,在除法运算中,应保证除数不为0;此时的递归为将临时变量b里的n-1个数来算24,判断是否可以满足题设要求。问题的递归主体及关键也在这里。

代码逻辑:

依据上述算法思想,不难想出应设置一个初始数组存储题设输入的一组数据;因为本题中设计除法相关操作,所以数据可能为浮点类型,但是由于浮点数在计算机中存储采用IEE754标准,存在精度丢失问题,所以对于浮点类型数据是否为0的判定不能使用“==”来判定,所以,还应定义一个函数来实现对浮点数是否为0的一个判断。

  1. 在C语言中,进行浮点数为0判断时,一般考虑判断该数的绝对值是否小于一个极小值ε,通常ε选10^-6。

    代码如下:

    #define ESP 1e-6bool isZero(double num) {return fabs(num) <= ESP;
    }
    
  2. 由上述算法思想中分析,设递归函数定义为,bool count24(double a[], int n),即:对有n个元素的a组数据进行算24操作。

    • 首先进入递归函数时应判断是否满足边界条件,即,当问题规模n=1时,判断该数是否等于24。

    • 在递归主体中,首先声明中间变量数组b,用于存储剩下的n-1个数以实现递归。

    • 通过枚举每一种可能的初始条件,以期寻求所有可能的解。

    • 每找到两个数后,将其与的n-2个数存入中间变量数组b中,再对这两个数进行算法思想中第二点所分析的6种情况进行计算。

    • 假设以a+b为例,其代码可描述为:

      b[m] = a[i] + a[j];
      if (count24(b, m + 1))return true;
      
    • 假设以a/b为例,其中b不为0,其代码可描述为:

      if (!isZero(a[j])) {b[m] = a[i] / a[j];if (count24(b, m + 1))return true;
      }
      
  3. 本题思想逻辑较前几题几乎并无不同,但在代码实现上有更大的难度,主要是对不同的情况做不同的递归处理,同时对于数据的处理也应考虑递归时数据作用域的不同对函数运算结果过的影响。比如用于存储题设输入元素的数组a,应为全局变量,因为在递归处理时,我们以中间变量b来进行运算,但同时也用到了数组a来为b进行赋值。所以在每一层递归中都用到了该变量,与递归层级无关,所以设置为全局变量能更好的进行代码的编写;或者将原始数组a作为形参传入递归函数,但是由于递归操作本来就对函数调用栈有较高的占用率,若再增加没有必要的形参数量,无疑是为函数调用栈带来了更大的负载。

  4. 至此,递归章节将告一段落,以上数题基本涵盖了递归在时间和空间复杂度要求不高的情况下能仅用递归能解决问题的几种基本问题模型。


代码整合:

//
// Created by Ss1Two on 2023/1/18.
//#include "stdio.h"
#include "stdbool.h"
#include "math.h"#define ESP 1e-6 ////判断浮点数num是否为0
bool isZero(double num) {return fabs(num) <= ESP;
}//存储题设输入的原始数据
double a[5];//把数组a中的n个元素进行算24判断
bool count24(double a[], int n) {//递归边界条件判定if (n == 1) {if (isZero(a[0] - 24))return true;elsereturn false;}//递归时中间变量数组double b[5];//枚举每一种可能的(先找两个数做运算的)初始条件for (int i = 0; i < n - 1; i++) {for (int j = i + 1; j < n; j++) {int m = 0;// m作为处理剩下的n-2个数时的下标for (int k = 0; k < n; k++) {//将非初始条件之外的n-2个数据存入中间变量b数组中if (k != i && k != j)b[m++] = a[k];}//将初始条件的两个值做加法运算,并存入中间变量b数组中//其中m+1==n-1b[m] = a[i] + a[j];//此时问题规模减一,即将b数组中的n-1个数,进行算24判断。//情况1:a + bif (count24(b, m + 1))return true;//情况2:a - bb[m] = a[i] - a[j];if (count24(b, m + 1))return true;//情况3:b - ab[m] = a[j] - a[i];if (count24(b, m + 1))return true;//情况4:a * bb[m] = a[i] * a[j];if (count24(b, m + 1))return true;//情况5:a / b ,其中b!=0if (!isZero(a[j])) {b[m] = a[i] / a[j];if (count24(b, m + 1))return true;}//情况6:b / a ,其中a!=0if (!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++) {scanf("%lf", &a[i]);}if (isZero(a[0]))break;if (count24(a, 4))printf("YES\n");elseprintf("NO\n");}return 0;
}

C r e a t e d ⋯ b y ⋯ S s 1 T w o ⋯ o n ⋯ 2023 / 01 / 18 Created\cdots by\cdots Ss1Two\cdots on \cdots 2023/01/18 Created⋯by⋯Ss1Two⋯on⋯2023/01/18

递归算法实例应用(五)相关推荐

  1. mysql数据库约束详解_基于MySQL数据库的数据约束实例及五种完整性约束介绍

    为了防止不符合规范的数据进入数据库,在用户对数据进行插入.修改.删除等操作时,DBMS自动按照一定的约束条件对数据进行监测,使不符合规范的数据不能进入数据库,以确保数据库中存储的数据正确.有效.相容. ...

  2. java中的递归算法_java递归算法实例分析

    递归算法设计的基本思想是: 对于一个复杂的问题,把原问题分解为若干个相对简单类同的子问题,继续下去直到子问题简单到能够直接求解,也就是说到了递推的出口,这样原问题就有递推得解. 在做递归算法的时候,一 ...

  3. 数据结构基础 之 递归算法实例讲解

    在数学与计算机科学中,递归是指在函数的定义中使用函数自身的方法. 递归算法是一种直接或者间接地调用自身算法的过程.在计算机编写程序中,递归算法对解决一大类问题是十分有效的,它往往使算法的描述简洁而且易 ...

  4. 递归算法实例应用(四)

    递归算法实例应用(四) 爬楼梯 (POJ 4017) Description 树老师爬楼梯,他可以每次走1级或者2级,输入楼梯的级数,求不同的走法数 例如:楼梯一共有3级,他可以每次都走一级,或者第一 ...

  5. Adroid游戏开发实例讲解(五)-哄娃神器之随机五彩泡(附源码)

    Adroid游戏开发实例讲解(五)-哄娃神器之随机五彩泡(附源码) 程序之美 泡泡 一直被孩子认为是神奇的东西.记得儿时,经常 趁大人不注意,偷偷抓一把洗衣粉撞到口袋里,然后自己悄悄的找来一个小瓶子, ...

  6. 递归与递归算法实例(java实现)

    一.递归介绍         递归算法(英语:recursion algorithm)在计算机科学中是指一种通过重复将问题分解为同类的子问题而解决问题的方法.绝大 多数编程语言支持函数的自调用,在这些 ...

  7. SQL经典实例(五)元数据查询

    列举模式中的表 Oracle select table_name from all_tables where owner = 'SCOTT'; MySQL select table_namefrom ...

  8. 卡尔曼滤波详解:一维卡尔曼滤波实例解析(五个公式以及各个参数的意义)

    一.引言 本文以rssi(接收信号强度)滤波为背景,结合卡尔曼的五个公式,设计 rssi 一维卡尔曼滤波器,用MATLAB语言实现一维卡尔曼滤波器,并附上代码和滤波结果图: 本文工分为以下几个部分: ...

  9. docker oracle创建实例_五分钟教你搭建oracle数据库环境

    环境:centos7 本来在linux安装一个oracle是一件痛苦的事情,这里我们使用docker安装 首先你要先安装docker 没有的话就 yum -y install docker 然后启动d ...

最新文章

  1. Ubuntu安装搜狗输入法
  2. org.hibernate.hql.ast.QuerySyntaxException: ? is not mapped
  3. 洛谷 P1064 金明的预算方案
  4. tomcat下list所有文件的目录
  5. 照片识别出错_云投诉丨四川德阳市民文明手册咋满篇乱码?回应:电脑识别问题,已全部收回...
  6. 面试刷题必看!Python中的5大排序算法及其实现代码
  7. Spring 的下载、安装和使用
  8. JAVA8内存最多设置多少,堆内存居高不下,JDK8自适应作怪
  9. 射频电路的原理及应用
  10. Cisco 防火墙 ASA DHCP 配置
  11. project不显示里程碑标志_如何在项目管理中使用里程碑
  12. flume系列之:清理HDFS上的tmp文件,把.gz.tmp文件变为.gz文件
  13. Nginx配置项调优
  14. 自我介绍html模板王,小学生个人自我介绍模板10篇
  15. 通达信版弘历软件指标_弘历软件多空王指标
  16. Nexus5刷Firefox OS 2.0
  17. 编译原理 —— 知识结构导图
  18. C语言时间库操作-->协调时转本地时
  19. Latex模版以及经验汇总
  20. 在vue项目中引入vuex(全局状态管理器)

热门文章

  1. (20181111)Fortran 产生随机数
  2. JavaScript-节点操作
  3. Google Android 原生Rom 下载地址及刷机教程--Factory Images for Nexus and Pixel Devices
  4. TensorFlow实现鸢尾花分类
  5. HTTP性能极限优化
  6. 我的世界服务器如何修改天气,我的世界怎么改变天气 我的世界改变天气指令代码大全...
  7. winrar 去广告_winRAR去广告版软件安装教程
  8. 面试心得(简历书写)
  9. 如何删除PDF水印,PDF删除水印的方法
  10. java运行时跟编译时的区别,欢迎大家指正