对于递归的最后一个问题,我们来看一下稍微复杂点的问题,这里的思想仍然是将问题分解为规模更小的子问题。
1、问题描述
例题:算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
2、问题分析
有 n 个数计算24,计算过程肯定是有两个数先算出结果,用这个结果再和剩下的 n-2 个数计算,于是问题变成了 n-1 个数求24的问题。我们可以
枚举需要先计算的两个数,计算这两个数所有可能的计算结果。
边界条件:什么时候计算结束呢,就是最后就剩下一个数了,这个数是24,成功,不是24,失败。
这里有一个问题,除法的结果是个浮点数,这里涉及到了比较浮点数是否相等的问题,不能直接用==,因为有些位上的数据可能省略了,应该用两数相减小于某个较小的值来决定是否相等。
#include<iostream>
using namespace std;
#define EPS 1e-6
double a[4];
bool iszero(double x)
{
return fabs(x) <= EPS;
}
//用数组a中的n个数计算24
bool count24(double a[], int n)
{
if (n == 1) //只有一个数了
{
if (iszero(a[0] - 24))
return true;
else
return false;
}
double b[4];
for (int i = 0; i < n-1; i++)
for (int j = i + 1; j < n; j++) //枚举两个数的组合
{
int m = 0; //还剩下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]; //两数两乘的结果也放b中
if (count24(b, n - 1))
return true;
b[m] = a[i] - a[j];
if (count24(b, n - 1))
return true;
b[m] = a[j] - a[i];
if (count24(b, n - 1))
return true;
b[m] = a[j] * a[i];
if (count24(b, n - 1))
return true;
if (!iszero(a[j])) //分母不是0,才进行除法运算
{
b[m] = a[i] / a[j];
if (count24(b, n - 1))
return true;
}
if (!iszero(a[i]))
{
b[m] = a[j] / a[i];
if (count24(b, n - 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;
}
abs,fabs,fabsf的使用
int abs(int i); //处理int类型的取绝对值
double fabs(double i); //处理double类型的取绝对值
float fabsf(float i); //处理float类型的取绝对值
fabs是取绝对值,但abs是取绝对值后再取整。
3、总结
- 浮点数比较是否相等,不能用 ==
- 将问题分解为规模更小的子问题