24点游戏问题
标签(空格分隔): OJ_算法
1. 题目描述
问题描述:给出4个1-10的数字,通过加减乘除,得到数字为24就算胜利
输入:4个1-10的数字。[数字允许重复,测试用例保证无异常数字]
输出:True or False
2. 问题求解(穷举法)
??利用穷举法,列出所有可能的表达式,然后计算表达式的值,问题便求解。
此问题可以分解为两步:
1. 列出所有可能的表达式
2. 计算法表达式(四则混合运算)的值
2.1 列出所有可能的表达式
表达式由输出的四个数字(1~10)、3个加减乘除(“+”、“-”、“*”、“/”)运算符以及括号组成。
分析所有组合(情况数):
1. 四个数字的所有排序:4*3*2=24
2. 四个数字中间的运算符的所有排列(由于运算符可以重复):4*4*4=64;
3. 添加括号分为以下三种情况:eg:a+b*c-d
类型 | 实例 | 数量(种) |
---|---|---|
无括号 | a+b*c-d | 1 |
1个括号 | (a+b)c-d;a+(b*c)-d;a+b(c-d);(a+b*c)-d;a+(b*c-d); | 5 |
2个括号 | (a+b)*(c-d) | 1 |
注:2个括号的其他类型通过去括号转化为一个括号类型
综上所述:所有表达式的排列为:24*64*(1+5+1)=10752(其中可能有重复)
代码实现:
//1.全排列:用递归的思想求出全排列
void swap(int &a, int &b)//交换连个元素
{
int tem;
tem = a;
a = b;
b = tem;
}
//计算所有操作数的全排列
void CalAllPermutation(int *a, int first, int length, vector<vector<string>>&permutation)
{
if (first == length - 1)//如果递归到深层时,到最后交换的元素即时最后一个元素时就打印出来
{
vector<string> permu(length);
char itoa_buffer[64];
for (int i = 0; i < length; i++)
{
sprintf(itoa_buffer, "%d", a[i]);
permu[i] = string(itoa_buffer);
}
permutation.push_back(permu);
}
else
{
for (int i = first; i < length; i++)
{//循环遍历使得当前位置后边的每一个元素都和当前深度的第一个元素交换一次
swap(a[first], a[i]);//使得与第一个元素交换
CalAllPermutation(a, first + 1, length, permutation);//深入递归,此时已确定前边的元素,处理后边子序列的全排列形式。
swap(a[first], a[i]);//恢复交换之前的状态
}
}
}
//计算所有运算符的组合
void CalOpSymbolCombination(string&sym, int ope_bit, int n, vector<string>&symbol)
{
if (ope_bit == n)
{
symbol.push_back(sym);
return;
}
for (int i = 0; i < 4; i++)
{
switch (i)
{
case 0:
sym[ope_bit] = ‘+‘;
break;
case 1:
sym[ope_bit] = ‘-‘;
break;
case 2:
sym[ope_bit] = ‘*‘;
break;
case 3:
sym[ope_bit] = ‘/‘;
break;
default:
break;
}
CalOpSymbolCombination(sym, ope_bit + 1, n, symbol);
}
}
2.2. 计算法表达式(四则混合运算)的值
2.2.1将中缀表达式变为后缀表达式
我们把平时所用的标准四则运算表达式,即“9+(3-1)×3+10÷2”叫做中缀表达式。因为所有的运算符号都在两数字的中间。
??中缀表达式 “9+(3-1)×3+10÷2” 转化为后缀表达式 “9 3 1 - 3 * + 10 2 / +” 。
规则:**中缀表达式转后缀表达式的方法:
1.遇到操作数:直接输出(添加到后缀表达式中)
2.栈为空时,遇到运算符,直接入栈
3.遇到左括号:将其入栈
4.遇到右括号:执行出栈操作,并将出栈的元素输出,直到弹出栈的是左括号,左括号不输出。
5.遇到其他运算符:加减乘除:弹出所有优先级大于或者等于该运算符的栈顶元素,然后将该运算符入栈
6.最终将栈中的元素依次出栈,输出。**。
代码实现(中缀表达式转后缀表达式):
// 2. 中缀表达式变后缀表达式并计算值
static char symbolPriority[4][4] = {
/* 符号优先级表 /* ‘+‘ ‘-‘ ‘*‘ ‘/‘ */
/* ‘+‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘-‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘*‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘,},
/* ‘/‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘ } };
vector<string> InfixToPostfixExpression(const string &infixExpression)
{
size_t i = 0;
vector<string> suffix_expression;
stack<char> symbol_stack;//符号栈
char ch = infixExpression[i++];
while (i <= infixExpression.size())
{
if (isdigit(ch))//1.遇到数字,直接输出
{
string digit;
while (isdigit(ch))
{
digit.push_back(ch);
ch = infixExpression[i++];
}
suffix_expression.push_back(digit);
}
else
{
if (symbol_stack.empty()||ch==‘(‘||symbol_stack.top()==‘(‘)//2.遇到符号:栈为空或符号为‘(‘或栈顶为‘(‘,符号直接入栈
{
symbol_stack.push(ch);
ch = infixExpression[i++];
}
else if (ch == ‘)‘)//3. 遇到右括号,弹出所有栈中符号直到左括号并输出(左括号不输出)
{
while (symbol_stack.top()!=‘(‘)
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
symbol_stack.pop();//弹出左括号,不输出
ch = infixExpression[i++];
}
else
{
while (!symbol_stack.empty())
{
char sym_priority = CompareSymbolPriorityPost(symbol_stack.top(), ch);
if (sym_priority == ‘>‘ || sym_priority == ‘=‘)//4.弹出优先级大于等于ch的所有符号
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
else
break;
}
symbol_stack.push(ch);//压入符号
ch = infixExpression[i++];
}
}
}
while (!symbol_stack.empty())
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
return suffix_expression;
}
char CompareSymbolPriorityPost(char sym1, char sym2)//中缀变后缀比较符号优先级
{
int index1 = IndexOfSymbol(sym1);
int index2 = IndexOfSymbol(sym2);
return symbolPriority[index1][index2];
}
int IndexOfSymbol(char sym)//符号优先级索引
{
int index;
switch (sym)
{
case ‘+‘:
index = 0;
break;
case ‘-‘:
index = 1;
break;
case ‘*‘:
index = 2;
break;
case ‘/‘:
index = 3;
break;
case ‘(‘:
index = 4;
break;
case ‘)‘:
index = 5;
break;
case ‘=‘:
index = 6;
break;
default:
break;
}
return index;
}
直接计算中缀表达是的值:
//运算符的优先关系比对表
static char SymbolRelation[7][7] = {
//‘+‘, ‘-‘, ‘*‘, ‘/‘, ‘(‘, ‘)‘, ‘=‘ //运算符2
{ ‘>‘, ‘>‘, ‘<‘, ‘<‘, ‘<‘, ‘>‘, ‘>‘ }, //‘+‘ //运算符1
{ ‘>‘, ‘>‘, ‘<‘, ‘<‘, ‘<‘, ‘>‘, ‘>‘ }, //‘-‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘<‘, ‘>‘, ‘>‘ }, //‘*‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘<‘, ‘>‘, ‘>‘ }, //‘/‘
{ ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘=‘, ‘>‘ }, //‘(‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘=‘, ‘>‘, ‘>‘ }, //‘)‘
{ ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘ ‘, ‘=‘ } };//‘=‘
double CalResultBySuffixExpression(string &infixExpresion)
{
stack<char> symbol_stack;//符号栈
stack<double> suffix_expression;//后缀表达式
char ch;
int i = 0;
infixExpresion += ‘=‘;
symbol_stack.push(‘=‘);
ch = infixExpresion[i++];
while (ch != ‘=‘ || symbol_stack.top() != ‘=‘)
{
if (isdigit(ch))//数字,直接输出
{
int ope_data = 0;
while (isdigit(ch))
{
ope_data = 10 * ope_data + ch - ‘0‘;//将字符串操作数转化为整数
ch = infixExpresion[i++];
}
suffix_expression.push(ope_data);
}
else
{
switch (CompareSymbolPriority(symbol_stack.top(), ch))
{
case ‘<‘://栈顶符号优先级低:继续压入符号进栈
symbol_stack.push(ch);
ch = infixExpresion[i++];
break;
case ‘=‘://括号配对:弹出栈顶括号,并丢弃该括号
symbol_stack.pop();
ch = infixExpresion[i++];
break;
case ‘>‘://栈顶优先级高
char sym_top = symbol_stack.top();
symbol_stack.pop();
double num2 = suffix_expression.top();
suffix_expression.pop();
double num1 = suffix_expression.top();
suffix_expression.pop();
double sub_result = CalSubExpressionResult(num1, num2, sym_top);
suffix_expression.push(sub_result);
break;
}
}
}
return suffix_expression.top();//返回后缀表达式
}
char CompareSymbolPriority(char sym1, char sym2)//比较符号优先级,直接计算值
{
int index1 = IndexOfSymbol(sym1);
int index2 = IndexOfSymbol(sym2);
return SymbolRelation[index1][index2];
}
int IndexOfSymbol(char sym)//符号优先级索引
{
int index;
switch (sym)
{
case ‘+‘:
index = 0;
break;
case ‘-‘:
index = 1;
break;
case ‘*‘:
index = 2;
break;
case ‘/‘:
index = 3;
break;
case ‘(‘:
index = 4;
break;
case ‘)‘:
index = 5;
break;
case ‘=‘:
index = 6;
break;
default:
break;
}
return index;
}
double CalSubExpressionResult(double a, double b, char symbol)
{
double result = 0.0;
switch (symbol)
{
case ‘+‘:
result = a + b;
break;
case ‘-‘:
result = a - b;
break;
case ‘*‘:
result = a*b;
break;
case ‘/‘:
result = a / b;
break;
default:
break;
}
return result;
}
2.2.2 计算后缀表达式的值
后缀表达式计算结果
规则:从左到右遍历表达式的每个数字和符号,遇到是数字就进栈,遇到是符号,就将处于栈顶两个数字出栈,进行运算,运算结果进栈,一直到最终获得结果。(初始化一个空栈,此栈用来对要运算的数字进行使用)
代码实现:
double CalSubExpressionResult(double a, double b, char symbol)
{
double result = 0.0;
switch (symbol)
{
case ‘+‘:
result = a + b;
break;
case ‘-‘:
result = a - b;
break;
case ‘*‘:
result = a*b;
break;
case ‘/‘:
result = a / b;
break;
default:
break;
}
return result;
}
//3. 计算后缀表达式的值
double CalPostfixExpressionValue(const vector<string>& postfixExpression)
{
stack<double> exp_data;
for (size_t i=0;i<postfixExpression.size();i++)
{
if(isdigit(postfixExpression[i][0]))
{
double data=atof(postfixExpression[i].c_str());
exp_data.push(data);
}
else
{
double num1,num2;
num2 = exp_data.top();
exp_data.pop();
num1 = exp_data.top();
exp_data.pop();
double temp_result= CalSubExpressionResult(num1,num2,postfixExpression[i][0]);
exp_data.push(temp_result);
}
}
return exp_data.top();
}
3. 24点游戏(穷举法)代码实现(全)
#include"Game24Points.h"
#include<cstdio>
#include<cctype>
#include<string>
#include<vector>
#include<stack>
#include <iostream>
using namespace std;
static void swap(int &a, int &b);//交换连个元素
static void CalAllPermutation(int *a, int first, int length, vector<vector<string>>&permutation);
static void CalOpSymbolCombination(string&sym, int ope_bit, int n, vector<string>&symbol);
static int IndexOfSymbol(char sym);
static char CompareSymbolPriority(char sym1, char sym2);//比较符号优先级
static char CompareSymbolPriorityPost(char sym1, char sym2);//中缀变后缀比较符号优先级
static std::vector<std::string> InfixToPostfixExpression(const std::string &infixExpression);
static double CalSubExpressionResult(double a, double b, char symbol);
static double CalResultBySuffixExpression(string &infixExpresion);
static double CalPostfixExpressionValue(const vector<string>& postfixExpression);
//运算符的优先关系比对表
static char SymbolRelation[7][7] = {
//‘+‘, ‘-‘, ‘*‘, ‘/‘, ‘(‘, ‘)‘, ‘=‘ //运算符2
{ ‘>‘, ‘>‘, ‘<‘, ‘<‘, ‘<‘, ‘>‘, ‘>‘ }, //‘+‘ //运算符1
{ ‘>‘, ‘>‘, ‘<‘, ‘<‘, ‘<‘, ‘>‘, ‘>‘ }, //‘-‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘<‘, ‘>‘, ‘>‘ }, //‘*‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘<‘, ‘>‘, ‘>‘ }, //‘/‘
{ ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘=‘, ‘>‘ }, //‘(‘
{ ‘>‘, ‘>‘, ‘>‘, ‘>‘, ‘=‘, ‘>‘, ‘>‘ }, //‘)‘
{ ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘<‘, ‘ ‘, ‘=‘ } };//‘=‘
static char symbolPriority[4][4] = {
/* 符号优先级表 /* ‘+‘ ‘-‘ ‘*‘ ‘/‘ */
/* ‘+‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘-‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘*‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘,},
/* ‘/‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘ } };
bool Game24Points(int a, int b, int c, int d)
{
int data[4] = { a,b,c,d };
vector<vector<string>> permutation;
string sym(3, ‘=‘);
vector<string> symbol;
string infix_expression;//中缀表达式
vector<string> postfix_expression;//后缀表达式
double expression_result = 0.0;
CalAllPermutation(data, 0, 4, permutation);//计算数字输入数字的全排列
CalOpSymbolCombination(sym, 0, 3, symbol);//计算表达式中间三个符号的所有组合
for (size_t i = 0; i < permutation.size(); i++)
{
for (size_t j = 0; j<symbol.size(); j++)
{
for (size_t k = 0; k < 7; k++)//添加括号
{
switch (k)
{
case 0://无括号类型
infix_expression = permutation[i][0] + symbol[j][0] + permutation[i][1] + symbol[j][1] + permutation[i][2]
+ symbol[j][2] + permutation[i][3];
break;
case 1://(a+b)*c-d类型
infix_expression = "(" + permutation[i][0] + symbol[j][0] + permutation[i][1] + ")" + symbol[j][1] + permutation[i][2]
+ symbol[j][2] + permutation[i][3];
break;
case 2://a+(b*c)-d类型
infix_expression = permutation[i][0] + symbol[j][0] + "(" + permutation[i][1] + symbol[j][1] + permutation[i][2] + ")"
+ symbol[j][2] + permutation[i][3];
break;
case 3://a+b*(c-d)类型
infix_expression = permutation[i][0] + symbol[j][0] + permutation[i][1] + symbol[j][1] + "(" + permutation[i][2]
+ symbol[j][2] + permutation[i][3] + ")";
break;
case 4://(a+b*c)-d类型
infix_expression = "(" + permutation[i][0] + symbol[j][0] + permutation[i][1] + symbol[j][1] + permutation[i][2]
+ ")" + symbol[j][2] + permutation[i][3];
break;
case 5://a+(b*c-d)类型
infix_expression = permutation[i][0] + symbol[j][0] + "(" + permutation[i][1] + symbol[j][1] + permutation[i][2]
+ symbol[j][2] + permutation[i][3] + ")";
break;
case 6://(a+b)*(c-d)类型
infix_expression = "(" + permutation[i][0] + symbol[j][0] + permutation[i][1] + ")" + symbol[j][1] + "(" + permutation[i][2]
+ symbol[j][2] + permutation[i][3] + ")";
break;
default:
break;
}
//expression_result = CalResultBySuffixExpression(infix_expression) - 24;
postfix_expression=InfixToPostfixExpression(infix_expression);
expression_result=CalPostfixExpressionValue(postfix_expression)-24;
if (expression_result<0.001&&expression_result>(-0.001))
{
cout<<infix_expression<<endl;
return true;
}
}
}
}
return false;
}
//1.全排列:用递归的思想求出全排列
void swap(int &a, int &b)//交换连个元素
{
int tem;
tem = a;
a = b;
b = tem;
}
void CalAllPermutation(int *a, int first, int length, vector<vector<string>>&permutation)
{
if (first == length - 1)//如果递归到深层时,到最后交换的元素即时最后一个元素时就打印出来
{
vector<string> permu(length);
char itoa_buffer[64];
for (int i = 0; i < length; i++)
{
sprintf(itoa_buffer, "%d", a[i]);
permu[i] = string(itoa_buffer);
}
permutation.push_back(permu);
}
else
{
for (int i = first; i < length; i++)
{//循环遍历使得当前位置后边的每一个元素都和当前深度的第一个元素交换一次
swap(a[first], a[i]);//使得与第一个元素交换
CalAllPermutation(a, first + 1, length, permutation);//深入递归,此时已确定前边的元素,处理后边子序列的全排列形式。
swap(a[first], a[i]);//恢复交换之前的状态
}
}
}
void CalOpSymbolCombination(string&sym, int ope_bit, int n, vector<string>&symbol)
{
if (ope_bit == n)
{
symbol.push_back(sym);
return;
}
for (int i = 0; i < 4; i++)
{
switch (i)
{
case 0:
sym[ope_bit] = ‘+‘;
break;
case 1:
sym[ope_bit] = ‘-‘;
break;
case 2:
sym[ope_bit] = ‘*‘;
break;
case 3:
sym[ope_bit] = ‘/‘;
break;
default:
break;
}
CalOpSymbolCombination(sym, ope_bit + 1, n, symbol);
}
}
// 2. 中缀表达式变后缀表达式并计算值
vector<string> InfixToPostfixExpression(const string &infixExpression)
{
size_t i = 0;
vector<string> suffix_expression;
stack<char> symbol_stack;//符号栈
char ch = infixExpression[i++];
while (i <= infixExpression.size())
{
if (isdigit(ch))//1.遇到数字,直接输出
{
string digit;
while (isdigit(ch))
{
digit.push_back(ch);
ch = infixExpression[i++];
}
suffix_expression.push_back(digit);
}
else
{
if (symbol_stack.empty()||ch==‘(‘||symbol_stack.top()==‘(‘)//2.遇到符号:栈为空或符号为‘(‘或栈顶为‘(‘,符号直接入栈
{
symbol_stack.push(ch);
ch = infixExpression[i++];
}
else if (ch == ‘)‘)//3. 遇到右括号,弹出所有栈中符号直到左括号并输出(左括号不输出)
{
while (symbol_stack.top()!=‘(‘)
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
symbol_stack.pop();//弹出左括号,不输出
ch = infixExpression[i++];
}
else
{
while (!symbol_stack.empty())
{
char sym_priority = CompareSymbolPriorityPost(symbol_stack.top(), ch);
if (sym_priority == ‘>‘ || sym_priority == ‘=‘)//4.弹出优先级大于等于ch的所有符号
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
else
break;
}
symbol_stack.push(ch);//压入符号
ch = infixExpression[i++];
}
}
}
while (!symbol_stack.empty())
{
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
suffix_expression.push_back(a);
}
return suffix_expression;
}
//3. 计算后缀表达式的值
double CalPostfixExpressionValue(const vector<string>& postfixExpression)
{
stack<double> exp_data;
for (size_t i=0;i<postfixExpression.size();i++)
{
if(isdigit(postfixExpression[i][0]))
{
double data=atof(postfixExpression[i].c_str());
exp_data.push(data);
}
else
{
double num1,num2;
num2 = exp_data.top();
exp_data.pop();
num1 = exp_data.top();
exp_data.pop();
double temp_result= CalSubExpressionResult(num1,num2,postfixExpression[i][0]);
exp_data.push(temp_result);
}
}
return exp_data.top();
}
double CalResultBySuffixExpression(string &infixExpresion)
{
stack<char> symbol_stack;//符号栈
stack<double> suffix_expression;//后缀表达式
char ch;
int i = 0;
infixExpresion += ‘=‘;
symbol_stack.push(‘=‘);
ch = infixExpresion[i++];
while (ch != ‘=‘ || symbol_stack.top() != ‘=‘)
{
if (isdigit(ch))//数字,直接输出
{
int ope_data = 0;
while (isdigit(ch))
{
ope_data = 10 * ope_data + ch - ‘0‘;//将字符串操作数转化为整数
ch = infixExpresion[i++];
}
suffix_expression.push(ope_data);
}
else
{
switch (CompareSymbolPriority(symbol_stack.top(), ch))
{
case ‘<‘://栈顶符号优先级低:继续压入符号进栈
symbol_stack.push(ch);
ch = infixExpresion[i++];
break;
case ‘=‘://括号配对:弹出栈顶括号,并丢弃该括号
symbol_stack.pop();
ch = infixExpresion[i++];
break;
case ‘>‘://栈顶优先级高
char sym_top = symbol_stack.top();
symbol_stack.pop();
double num2 = suffix_expression.top();
suffix_expression.pop();
double num1 = suffix_expression.top();
suffix_expression.pop();
double sub_result = CalSubExpressionResult(num1, num2, sym_top);
suffix_expression.push(sub_result);
break;
}
}
}
return suffix_expression.top();//返回后缀表达式
}
char CompareSymbolPriority(char sym1, char sym2)//比较符号优先级,直接计算值
{
int index1 = IndexOfSymbol(sym1);
int index2 = IndexOfSymbol(sym2);
return SymbolRelation[index1][index2];
}
char CompareSymbolPriorityPost(char sym1, char sym2)//中缀变后缀比较符号优先级
{
int index1 = IndexOfSymbol(sym1);
int index2 = IndexOfSymbol(sym2);
return symbolPriority[index1][index2];
}
int IndexOfSymbol(char sym)//符号优先级索引
{
int index;
switch (sym)
{
case ‘+‘:
index = 0;
break;
case ‘-‘:
index = 1;
break;
case ‘*‘:
index = 2;
break;
case ‘/‘:
index = 3;
break;
case ‘(‘:
index = 4;
break;
case ‘)‘:
index = 5;
break;
case ‘=‘:
index = 6;
break;
default:
break;
}
return index;
}
double CalSubExpressionResult(double a, double b, char symbol)
{
double result = 0.0;
switch (symbol)
{
case ‘+‘:
result = a + b;
break;
case ‘-‘:
result = a - b;
break;
case ‘*‘:
result = a*b;
break;
case ‘/‘:
result = a / b;
break;
default:
break;
}
return result;
}
main 函数
#include <iostream>
#include"Game24Points.h"
using namespace std;
int main()
{
int a,b,c,d;
do
{
cin>>a>>b>>c>>d;
if(!Game24Points(a,b,c,d))
{
cout<<"No Answer"<<endl;
}
} while (1);
system("pause");
return 0;
}
24点游戏问题优化解:
/******************************************************************************
Copyright (C), 2001-2013, Huawei Tech. Co., Ltd.
******************************************************************************
File Name :
Version :
Author :
Created : 2013/03/12
Last Modified :
Description :
Function List :
History :
1.Date : 2013/03/12
Author :
Modification: Created file
******************************************************************************/
#include"OJ.h"
#include<string>
#include<vector>
#include<stack>
#include <iostream>
#include<algorithm>
#include<sstream>
using namespace std;
void CalOpSymbolSet(char(*symbol_set)[3]);
static int IndexOfSymbol(char sym);
static char CompareSymbolPriority(char sym1, char sym2);//比较符号优先级
static void PopSymbolToPostfixExpression(stack<char> &symbol_stack, vector<string> &postfix_expression);
static vector<string> InfixToPostfixExpression(const string &infix_expression);
static string int_to_string(const int n);//int to string
static double CalSubExpressionResult(double a, double b, char symbol);
static double CalPostfixExpressionValue(const vector<string>& postfix_expression);
//运算符的优先关系比对表
static char symbol_priority[4][4] = {
/* 符号优先级表 /* ‘+‘ ‘-‘ ‘*‘ ‘/‘ */
/* ‘+‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘-‘ */{ ‘=‘, ‘=‘, ‘<‘, ‘<‘,},
/* ‘*‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘,},
/* ‘/‘ */{ ‘>‘, ‘>‘, ‘=‘, ‘=‘ } };
bool Game24Points(int a, int b, int c, int d)
{
int num_array[4] = { a,b,c,d };
char symbol_set[64][3];//运算符号组合
string infix_expression;//中缀表达式
vector<string> postfix_expression;//后缀表达式
double expression_result = 0.0;
//1. 计算符号组合
int count = 0;
CalOpSymbolSet(symbol_set);
//2.计算输入数字的字典序排列
sort(num_array, num_array + 4);
do
{
for (int i = 0; i < 64; i++)
for (int j = 0; j < 7; j++)
{
switch (j)
{
case 0://无括号类型
infix_expression = int_to_string(num_array[0]) + symbol_set[i][0] + int_to_string(num_array[1]) + symbol_set[i][1] + int_to_string(num_array[2])
+ symbol_set[i][2] + int_to_string(num_array[3]);
break;
case 1://(a+b)*c-d类型
infix_expression = "(" + int_to_string(num_array[0]) + symbol_set[i][0] + int_to_string(num_array[1]) + ")" + symbol_set[i][1] + int_to_string(num_array[2])
+ symbol_set[i][2] + int_to_string(num_array[3]);
break;
case 2://a+(b*c)-d类型
infix_expression = int_to_string(num_array[0]) + symbol_set[i][0] + "(" + int_to_string(num_array[1]) + symbol_set[i][1] + int_to_string(num_array[2]) + ")"
+ symbol_set[i][2] + int_to_string(num_array[3]);
break;
case 3://a+b*(c-d)类型
infix_expression = int_to_string(num_array[0]) + symbol_set[i][0] + int_to_string(num_array[1]) + symbol_set[i][1] + "(" + int_to_string(num_array[2])
+ symbol_set[i][2] + int_to_string(num_array[3]) + ")";
break;
case 4://(a+b*c)-d类型
infix_expression = "(" + int_to_string(num_array[0]) + symbol_set[i][0] + int_to_string(num_array[1]) + symbol_set[i][1] + int_to_string(num_array[2])
+ ")" + symbol_set[i][2] + int_to_string(num_array[3]);
break;
case 5://a+(b*c-d)类型
infix_expression = int_to_string(num_array[0]) + symbol_set[i][0] + "(" + int_to_string(num_array[1]) + symbol_set[i][1] + int_to_string(num_array[2])
+ symbol_set[i][2] + int_to_string(num_array[3]) + ")";
break;
case 6://(a+b)*(c-d)类型
infix_expression = "(" + int_to_string(num_array[0]) + symbol_set[i][0] + int_to_string(num_array[1]) + ")" + symbol_set[i][1] + "(" + int_to_string(num_array[2])
+ symbol_set[i][2] + int_to_string(num_array[3]) + ")";
break;
default:
break;
}
postfix_expression = InfixToPostfixExpression(infix_expression);
expression_result=CalPostfixExpressionValue(postfix_expression)-24;
if (expression_result<0.001&&expression_result>(-0.001))
{
cout<<infix_expression<<endl;
return true;
}
}
} while (next_permutation(num_array, num_array + 4));//求下一个字典序排列
return false;
}
string int_to_string(const int n)
{
ostringstream oss;//创建一个流
oss << n;//把值传递如流中
return oss.str();//返回转换后的字符串
}
//1. 计算符号组合
void CalOpSymbolSet(char(*symbol_set)[3])//计算运算符组合(‘+’、‘-’、‘*’、‘/‘)
{
char sym[4] = { ‘+‘,‘-‘,‘*‘,‘/‘ };
for (int i = 0; i < 4; i++)
for (int j = 0; j < 4;j++)
for (int k = 0; k < 4; k++)
{
(*symbol_set)[0] = sym[i];
(*symbol_set)[1] = sym[j];
(*symbol_set)[2] = sym[k];
++symbol_set;
}
}
//3. 中缀表达式变后缀表达式并计算值
vector<string> InfixToPostfixExpression(const string &infix_expression)
{
size_t i = 0;
vector<string> postfix_expression;
stack<char> symbol_stack;//符号栈
char ch = infix_expression[i++];
while (i <= infix_expression.size())
{
if (isdigit(ch))//1.遇到数字,直接输出
{
string digit;
while (isdigit(ch))
{
digit.push_back(ch);
ch = infix_expression[i++];
}
postfix_expression.push_back(digit);
}
else
{
if (symbol_stack.empty()||ch==‘(‘||symbol_stack.top()==‘(‘)//2.遇到符号:栈为空或符号为‘(‘或栈顶为‘(‘,符号直接入栈
{
symbol_stack.push(ch);
ch = infix_expression[i++];
}
else if (ch == ‘)‘)//3. 遇到右括号,弹出所有栈中符号直到左括号并输出(左括号不输出)
{
while (symbol_stack.top()!=‘(‘)
{
PopSymbolToPostfixExpression(symbol_stack, postfix_expression);
}
symbol_stack.pop();//弹出左括号,不输出
ch = infix_expression[i++];
}
else
{
while (!symbol_stack.empty())
{
char sym_priority = CompareSymbolPriority(symbol_stack.top(), ch);
if (sym_priority == ‘>‘ || sym_priority == ‘=‘)//4.弹出优先级大于等于ch的所有符号
PopSymbolToPostfixExpression(symbol_stack, postfix_expression);
else
break;
}
symbol_stack.push(ch);//压入符号
ch = infix_expression[i++];
}
}
}
while (!symbol_stack.empty())//弹出栈中剩余符号
{
PopSymbolToPostfixExpression(symbol_stack, postfix_expression);
}
return postfix_expression;
}
//弹出栈中符号并输出到后缀表达式
void PopSymbolToPostfixExpression(stack<char> &symbol_stack, vector<string> &postfix_expression)
{
if (symbol_stack.empty())
return;
string a(1, ‘#‘);
a[0] = symbol_stack.top();
symbol_stack.pop();
postfix_expression.push_back(a);
}
//3. 计算后缀表达式的值
double CalPostfixExpressionValue(const vector<string>& postfix_expression)
{
stack<double> exp_data;
for (size_t i=0;i<postfix_expression.size();i++)
{
if(isdigit(postfix_expression[i][0]))
{
double data = atof(postfix_expression[i].c_str());
exp_data.push(data);
}
else
{
double num1,num2;
num2 = exp_data.top();
exp_data.pop();
num1 = exp_data.top();
exp_data.pop();
double temp_result= CalSubExpressionResult(num1,num2,postfix_expression[i][0]);
exp_data.push(temp_result);
}
}
return exp_data.top();
}
char CompareSymbolPriority(char sym1, char sym2)//中缀变后缀比较符号优先级
{
int index1 = IndexOfSymbol(sym1);
int index2 = IndexOfSymbol(sym2);
return symbol_priority[index1][index2];
}
int IndexOfSymbol(char sym)//符号优先级索引
{
int index;
switch (sym)
{
case ‘+‘:
index = 0;
break;
case ‘-‘:
index = 1;
break;
case ‘*‘:
index = 2;
break;
case ‘/‘:
index = 3;
break;
case ‘(‘:
index = 4;
break;
case ‘)‘:
index = 5;
break;
case ‘=‘:
index = 6;
break;
default:
break;
}
return index;
}
double CalSubExpressionResult(double a, double b, char symbol)
{
double result = 0.0;
switch (symbol)
{
case ‘+‘:
result = a + b;
break;
case ‘-‘:
result = a - b;
break;
case ‘*‘:
result = a*b;
break;
case ‘/‘:
result = a / b;
break;
default:
break;
}
return result;
}
参考:
计算表达式值:http://www.cnblogs.com/heyonggang/p/3359565.html
中缀表达式、后缀表达式:
1. http://www.cnblogs.com/heyonggang/p/3359565.html
2. http://www.cnblogs.com/mygmh/archive/2012/10/06/2713362.html
3. http://blog.csdn.net/girlkoo/article/details/17435717
4. http://www.acmerblog.com/infix-to-postfix-6072.html
24点游戏,集合解法
http://www.cnblogs.com/Quincy/archive/2012/03/26/2418546.html