问题描述:
给出4个小于10的正整数,可以使用+-*/()的运算将这4个数连接起来得到一个表达式。问,是否存在一种计算方式可以使表达式的结果为24。
输入:
输入多行数据,每行包括4个小于10的正整数。最后一行数据为4个0,作为数据的终止。
输出:
对于每一组数据,如果可以得到24,则输出“YES”,否则输出“NO”。
样例输入与输出:
5 5 5 1
YES
1 1 4 2
NO
0 0 0 0
问题的分析及解决:
这个问题就是我们所熟知的算24这个数学游戏。我们先跳出如果用代码实现这个问题,思考一下,当给我们4个数字时,我们是用什么方式得出是否可以计算24这个问题。大部分人所用的方法都是连拼带凑的方法得出结论的,即尝试将几个数字进行+-*/运算,拼凑出是否为24。如果将这种思想转化为算法思想,我们首先想出的便是枚举,即把数字两两计算,并且把所有的可能性都列举出来,例如:我们已知A,B,C,D这4个数字,我们先尝试A,B;A,C;A,D;B,C;B,D;C,D这6组数的+-*/,并把这6组数得出的结果与剩下的值重复进行上述的操作,直至剩余最后2个数尝试进行+-*/,看看是否能够得出24这个值,如果最终的结果为24,那么输出YES,否则输出NO。
在编写代码的过程中,我们会发现,如果用非递归的方式写代码,将会嵌套好几层for循环,且代码显得非常的冗余,所以在循环重复计算时,我们引入递归的方式,减少冗余的代码量。且这题在解决多重循环的问题上,类似N皇后问题的处理方法。由于N皇后问题中的N参数未知,所以通过递归可以避免手写N重循环的问题。本题其实已知循环的层数了,可以通过递归来提升代码的简洁度。代码实现难度相对不大。
代码
#include <iostream>
#include <math.h>
using namespace std;
double a[5];//存储录入的4个参数
#define EPS 1e-6
bool isZero(double x)//判断是否为0
{
return fabs(x) <= EPS;
}
bool Calculate24(double a[], int n)
{
if (n == 1)
{
if (isZero(a[0] - 24))
return true;
else
return false;
}
double b[5];//用于存数组a中未计算的参数及完成计算的参数的值
for (int i = 0; i < n - 1; i++)
for (int j = i + 1; j < n; j++)
{
int m = 0;
for (int k = 0; k < n; k++)//将数组a中未计算的参数放入数组b中
if (k != i && k != j)
b[m++] = a[k];//m自增
b[m] = a[i] + a[j];
if (Calculate24(b, m + 1))
return true;
b[m] = a[i] - a[j];
if (Calculate24(b, m + 1))
return true;
b[m] = a[j] - a[i];
if (Calculate24(b, m + 1))
return true;
b[m] = a[i] * a[j];
if (Calculate24(b, m + 1))
return true;
if (!isZero(a[i]))
{
b[m] = a[i] / a[j];
if (Calculate24(b, m + 1))
return true;
}
if (!isZero(a[j]))
{
b[m] = a[j] / a[i];
if (Calculate24(b, m + 1))
return true;
}
}
return false;
}
void main()
{
while (true)
{
for (int i = 0; i < 4; i++)
cin >> a[i];
if (isZero(a[0]))
break;
if (Calculate24(a, 4))
cout << "YES" << endl;
else
cout << "NO" << endl;
}
}
代码细节简评:
1)由于浮点数是不能用==来判断两个浮点数是否相等的,所以在这我们定义了一个isZero(double x)函数进行判断。通过2个浮点数相减绝对值小于 1e-16,来判断2个浮点数是否相等。
2)在进行除法时,我们要判断被除数是否为0
3)整体难度和思路的难度不算太大,但是码量有点大,撸的时候要细心一点。