问题:
给出 4个小于 10 个正整数,你可以使用加减乘除 4种运算以及括号把这 4 个数连接起来得到一个表达式。现在的问题是,是否存在一种方式使得得到的表达式的结果等于 24。
这里加减乘除以及括号的运算结果和运算的优先级跟我们平常的定义一致(这里的除法定义是实数除法)。
分析:
我们可以采用递归回溯的方法来尝试所有可能的运算组合。具体来说,就是对于每一个数字,我们尝试把它和后面的数字用加减乘除四种运算连接起来,然后再对结果继续递归处理,直到处理完所有的数字。
在递归的过程中,我们要注意运算的优先级,比如乘法和除法要比加法和减法先计算。为了处理这个问题,我们可以用括号来改变运算的顺序。
算法思想:
这个程序的算法思想是基于回溯法(Backtracking)来解决24点游戏问题。24点游戏是一种数学游戏,目标是通过给定的四个数字(每个数字可以使用一次),使用加、减、乘、除四则运算,以及括号来改变运算顺序,使得最后的结果为24。
1. 输入处理:程序首先接收用户输入的四个整数,并将它们存储在一个vector<int>类型的变量input中。如果用户输入的是四个0,则程序结束循环并退出。
2. 类型转换:由于浮点数运算的需要(例如除法可能产生小数),程序将input中的整数转换为double类型,并存储在另一个vector<double>类型的变量nums中。
3. 递归回溯:程序定义了一个递归函数calculate24,该函数尝试通过所有可能的数字组合和运算来找到一种方案,使得最终的结果为24。
• 终止条件:如果nums中只剩下一个数字,函数检查这个数字是否等于24(考虑到浮点数精度问题,使用fabs(nums[0]-24)==0来判断是否接近24)。
• 递归步骤:对于nums中的每一对不同的数字(nums[i]和nums[j]),函数尝试四种运算(加、减、乘、除)。对于每种运算,它创建一个新的vector<double>类型的变量next_round,其中包含了除了这对数字之外的其他数字以及这对数字运算后的结果。然后,函数递归调用自身,传入nextround作为参数。
• 回溯:如果当前运算组合不能得到24(即递归调用返回false),则函数通过next_round.pop_back()撤销刚刚添加的运算结果,尝试下一种运算。
4. 输出结果:对于每组输入的数字,如果calculate24函数返回true,则输出"YES",表示可以找到一种运算方案使得结果为24;否则输出"NO"。
这个算法通过递归和回溯的方式,穷举了所有可能的数字和运算组合,从而判断是否存在一种方案使得给定的四个数字通过四则运算得到24。
代码:
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
首先,引入了四个头文件,分别是输入输出流、数学库、向量容器和算法库。这些库为程序提供了输入输出、数学运算、动态数组和排序等功能。
if(nums.size()==1)
{
return fabs(nums[0]-24)==0;
}
如果向量中只剩下一个数字,就判断这个数字是否等于24(考虑到浮点数精度问题,使用fabs函数取绝对值并比较是否接近0)。
for(int i=0;i<nums.size();++i)
{
for(int j=0;j<nums.size();++j)
{
if(i!=j)
使用两层循环遍历向量中的每对数字,确保不会使用相同的数字进行运算。
vector<double> nextround;
for(int k=0;k<nums.size();++k)
{
if(k!=i&&k!=j)
{
nextround.push_back(nums[k]);
}
}
创建一个新的向量nextround,用于存储除了当前选中的两个数字外的其他数字。
遍历四种运算:加、减、乘、除。
if(op==0)
{
nextround.push_back(nums[i]+nums[j]);
}
else if(op == 1)
{
nextround.push_back(nums[i]-nums[j]);
}
else if(op==2)
{
nextround.push_back(nums[i]*nums[j]);
}
else if(op==3&&fabs(nums[j])>0)
{
nextround.push_back(nums[i]/nums[j]);
}
根据运算类型,将计算结果添加到next_round向量中。注意,除法运算时要检查除数是否为零,以避免除零错误。
if(calculate24(nextround))
{
return true;
}
递归调用calculate24函数,检查新的数字集合是否可以得到24。如果可以,就返回true。
如果所有可能的运算和组合都不能得到24,就返回false。注意,每次尝试完一种运算后,要从nextround中移除最后添加的元素,以便进行下一次尝试。
定义主函数。
vector<int> input(4);
创建一个大小为4的整数向量input,用于存储用户输入的数字。使用while循环不断读取用户输入。
for (int i = 0; i < 4; ++i)
{
cin >> input[i];
}
使用循环读取四个数字。
if (input[0] == 0 && input[1] == 0 && input[2] == 0 && input[3] == 0)
{
break;
}
如果输入的是四个0,就跳出循环,结束程序。
vector<double> nums(input.begin(), input.end());
if (calculate24(nums))
{
cout << "YES" << endl;
}
else
{
cout << "NO" << endl;
}
将input向量转换为double类型的nums向量,并调用calculate24函数。根据返回值输出"YES"或"NO"。
源代码:
#include <iostream>
#include <cmath>
#include <vector>
#include <algorithm>
using namespace std;
bool calculate24(vector<double>& nums)
{
if(nums.size()==1)
{
return fabs(nums[0]-24)==0;
}
for(int i=0;i<nums.size();++i)
{
for(int j=0;j<nums.size();++j)
{
if(i!=j)
{
vector<double> next_round;
for(int k=0;k<nums.size();++k)
{
if(k!=i&&k!=j)
{
nextround.push_back(nums[k]);
}
}
for(int op=0;op<4;++op)
{
if(op==0)
{
nextround.push_back(nums[i]+nums[j]);
}
else if(op == 1)
{
nextround.push_back(nums[i]-nums[j]);
}
else if(op==2)
{
nextround.push_back(nums[i]*nums[j]);
}
else if(op==3&&fabs(nums[j])>0)
{
nextround.push_back(nums[i]/nums[j]);
}
if(calculate24(nextround))
{
return true;
}
nextround.pop_back();
}
}
}
}
return false;
}
int main()
{
vector<int> input(4);
while (true) {
for (int i = 0; i < 4; ++i)
{
cin >> input[i];
}
if (input[0] == 0 && input[1] == 0 && input[2] == 0 && input[3] == 0)
{
break;
}
vector<double> nums(input.begin(), input.end());
if (calculate24(nums))
{
cout << "YES" << endl;
} else
{
cout << "NO" << endl;
}
}
return 0;
}