题解 | #24点游戏算法#
24点游戏算法
http://www.nowcoder.com/practice/fbc417f314f745b1978fc751a54ac8cb
题目的主要信息:
给出4个1-10的数字,通过加减乘除运算,得到数字为24就算胜利,除法指实数除法运算,本题对数字选取顺序无要求,但每个数字仅允许使用一次,且不考虑括号运算。
方法一:
首先将给定的四个数字提取出来,然后对四个数字的所有排列枚举一遍,每个排列都判断是否能完成24点计算,如果能,则结束循环,输出运算。判断是否能完成24点也是用暴力枚举的方式,首先枚举第一个运算符,然后再枚举第二个运算符,枚举第三个运算符,如果当前运算符的选择可以的到结果24则结束递归。 具体做法:
#include <bits/stdc++.h>
using namespace std;
bool get(double a, double b, char& op1) {//穷举最后一个符号
if (a + b == 24) {
op1 = '+';
return true;
}
if (a - b == 24) {
op1 = '-';
return true;
}
if (a * b == 24) {
op1 = '*';
return true;
}
if (a / b == 24) {
op1 = '/';
return true;
}
return false;
}
bool get(double a, double b, double c, char& op1, char& op2) {//穷举第二个运算符
if (get(a + b, c, op2)) {
op1 = '+';
return true;
}
if (get(a - b, c, op2)) {
op1 = '-';
return true;
}
if (get(a * b, c, op2)) {
op1 = '*';
return true;
}
if (get(a / b, c, op2)) {
op1 = '/';
return true;
}
return false;
}
bool get(double a, double b, double c, double d, char& op1, char& op2, char& op3) {//穷举第一个符号
//+ - * /每一种方法都穷举一遍,递归计算
if (get(a + b, c, d, op2, op3)) {
op1 = '+';
return true;
}
if (get(a - b, c, d, op2, op3)) {
op1 = '-';
return true;
}
if (get(a * b, c, d, op2, op3)) {
op1 = '*';
return true;
}
if (get(a / b, c, d, op2, op3)) {
op1 = '/';
return true;
}
return false;
}
int main() {
vector<double> num(4, 0);
while (cin >> num[0] >> num[1] >> num[2] >> num[3]) {
sort(num.begin(), num.end());
bool flag = false;
char op[3];
do {
if (get(num[0], num[1], num[2], num[3], op[0], op[1], op[2])) {//如果这个排列可以完成24点运算
cout << "true" << endl;
flag = true;//找了一种解法,flag为true
break;
}
} while (next_permutation(num.begin(), num.end()));//每个排列都遍历一遍
if (!flag){
//没有找到解法
cout << "false" << endl;
}
}
}
复杂度分析:
- 时间复杂度:,虽然过程繁琐,但是说到底是对4个数的运算进行枚举,只需要常数时间。
- 空间复杂度:,因为是对4个数进行运算,递归栈的大小是常数。
方法二:
方法一中我们枚举了所有操作数可能的顺序,同样的,我们也可以对运算符进行枚举。最终我们只需在三个地方用到运算符,每个地方运算符都可能是中的一种,总共有4x4x4种可能,我们枚举所有操作数的顺序和运算符的64种可能,计算当前操作数顺序和运算符顺序下的结果,如果结果为24,则结束枚举,输出运算过程。运算符的64种顺序枚举用三个for循环实现,calculator函数计算当前操作数顺序和运算符的结果。
具体做法:
#include <bits/stdc++.h>
using namespace std;
vector<char> op={'+', '-', '*', '/'};
vector<char> operation;//当前的运算符顺序
double calculator(vector<int> num, vector<char> operation) {//计算当前顺序的操作数和运算符的结果
double sum=num[0];
for(int i=0,j=1;i<operation.size();i++,j++){
switch(operation[i]){
case '+':
sum += num[j];
break;
case '-':
sum -= num[j];
break;
case '*':
sum *= num[j];
break;
case '/':
sum /= num[j];
break;
}
}
return sum;
}
bool dfs(int a, int b, int c, int d) {
vector<int> num = {a, b, c, d};
for(int i=0;i<op.size();i++){//三个循环枚举所有的操作符顺序可能
for(int j=0;j<op.size();j++){
for(int k=0;k<op.size();k++){
operation = {op[i], op[j], op[k]};//枚举所有可能的运算符顺序
double sum = calculator(num, operation);//计算结果
if(sum == 24.0){//若结果为24则结束枚举
return true;
}
}
}
}
return false;
}
int main() {
vector<int> num(4,0);
while (cin >> num[0] >> num[1] >> num[2] >> num[3]){
sort(num.begin(), num.end());
bool flag = false;
char op[3];
do {
if (dfs(num[0], num[1], num[2], num[3])) {//如果这个操作数排列可以完成24点运算
cout << "true" << endl;
flag = true;
break;
}
} while (next_permutation(num.begin(), num.end()));//每个排列都遍历一遍
if (!flag){
//没有找到解法
cout << "false" << endl;
}
}
}
复杂度分析:
- 时间复杂度:,虽然有三个for循环,但是总共只有64种可能,只需要常数时间。
- 空间复杂度:,只用了常数空间。