24点游戏问题

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

时间: 2024-10-29 15:35:25

24点游戏问题的相关文章

[华为机试练习题]44.24点游戏算法

题目 注意: 6 + 2 * 4 + 10 = 24 不是一个数字一个数字的计算 代码 /*--------------------------------------- * 日期:2015-07-03 * 作者:SJF0115 * 题目:24点游戏算法 * 来源:华为机试练习题 -----------------------------------------*/ #include <iostream> #include <string> #include <vector&

24点游戏

题目描述 给出4个正整数操作数,你的任务是使用运算符(+,-,*,/)和括号对操作数进行计算,分析是否能得到24,每个操作数只能使用1次,运算符和括号可以多次使用,注意所有的中间结果都是整数. 输入 输入包括多行,每行4个正整数,范围是[1,13],输入以0 0 0 0标记结束 输出 若输入的4个操作数能计算出24,输出Yes,否则输出No 样例输入 1 1 1 1 2 5 7 8 0 0 0 0 样例输出 No Yes #include<iostream>   #include<str

微信公众平台开发—24点游戏

一.源码 package org.xs.dntown.wx.game24.modules.web; import java.text.NumberFormat; import java.util.Arrays; import java.util.Date; import java.util.List; import java.util.Random; import javax.script.ScriptEngine; import javax.script.ScriptEngineManager

24点游戏(dfs)

24点游戏 Time Limit: 3000/1000MS (Java/Others)     Memory Limit: 65535/65535KB (Java/Others) Submit Status 2424点就是给你一串数字,问你是否通过加减乘除括号构成2424点. 沈爷觉得这个很好玩,就决定考考你,给你44个数,可以交换位置,可以用加减乘除和括号,是否能构成2424点呢? 注意哦~这里的除法并不是整数除法,比如样例 Input 第一行TT,表示有多少组测试数据,1≤T≤501≤T≤5

cdoj 1252 24点游戏 dfs

24点游戏 Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://acm.uestc.edu.cn/#/problem/show/1252 Description 24点就是给你一串数字,问你是否通过加减乘除括号构成24点. 沈爷觉得这个很好玩,就决定考考你,给你4个数,可以交换位置,可以用加减乘除和括号,是否能构成24点呢? 注意哦~这里的除法并不是整数除法,比如样例 Input 第一行T,表示有多少组测试数据,1≤T≤50 接下来T行,每行4

24点游戏计算器 (简单四则运算)(c++)

24点游戏计算器 (简单四则运算)(c++):https://github.com/liuxinig/cpp_1001/blob/master/24dian_siZeIN.txt 1 //24点统计 2 3 #include <iostream> 4 #include <cmath> 5 using namespace std; 6 #define N 14 7 //a数组存四个数字 8 int cixu[3],fuHao[3],p[N],sum = 0; 9 float a0[4

24点游戏计算器 (加、减、乘、除、阶乘、导数)(c++)

24点游戏计算器 (加.减.乘.除.阶乘.导数)(c++):https://github.com/liuxinig/cpp_1001/blob/master/24dian_fuZaIN.txt 1 //24点统计 2 3 #include <iostream> 4 #include <cmath> 5 using namespace std; 6 #define N 14 7 //a数组存四个数字 8 int cixu[3],fuHao[3],p[N],sum = 0; 9 flo

编程之美-1.16 24点游戏

一.问题描述 给玩家4张牌,每张牌牌面值在1~13之间,允许其中有数值相同的牌.采用加.减.乘.除四则运算,允许中间运算存在小数,并且可以使用括号,但每张牌只能使用一次,尝试构造一种表达式,使其运算结果为24. 如 输入:3 3 7 7 输出:(((3)/(7))+(3))*(7) 二.程序实现原理 遍历所有可能的组合,直到找到一个符合条件的组合或者遍历所有情况没有找到满足的组合,具体详见代码注释 三.程序基本实现 #include<iostream> #include<string&g

经典趣味24点游戏程序设计(python)

一.游戏玩法介绍: 24点游戏是儿时玩的主要益智类游戏之一,玩法为:从一副扑克中抽取4张牌,对4张牌使用加减乘除中的任何方法,使计算结果为24.例如,2,3,4,6,通过( ( ( 4 + 6 ) - 2 ) * 3 )  = 24,最快算出24者剩. 二.设计思路: 由于设计到了表达式,很自然的想到了是否可以使用表达式树来设计程序.本程序的确使用了表达式树,也是程序最关键的环节.简要概括为:先列出所有表达式的可能性,然后运用表达式树计算表达式的值.程序中大量的运用了递归,各个递归式不是很复杂,

bzoj1215 24点游戏

Description 为了培养小孩的计算能力,大人们经常给小孩玩这样的游戏:从1付扑克牌中任意抽出4张扑克,要小孩用“+”.“-”.“×”.“÷”和括号组成一个合法的表达式,并使表达式的值为24点.这种游戏就是所谓的“24点游戏”.请你编程求出对于给出的任意4个正整数a.b.c.d,请你编程求出这4个整数能组成多少个值为24的不同表达式. Input 输入共一行,为4个正整数a.b.c.d (0<=a,b,c,d<=100) Output 输出由a.b.c.d组成的值为24表达式个数,如没有