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-d1
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

  • 0
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
问题一 字串变换 描述: 已知有两个字串 A, B 及一组字串变换的规则: A1 -> B1 A2 -> B2 规则的含义为:在 A中的子串 A1 可以变换为 B1、A2 可以变换为 B2 … 例如:A='abcd' B='xyz' 变换规则为: ‘abc’ -> ‘xu’ ‘ud’ -> ‘y’ ‘y’ -> ‘yz’ 则此时,A 可以经过一系列的变换变为 B,其变换的过程为: ‘abcd’ -> ‘xud’ -> ‘xy’ -> ‘xyz’ 共进行了三次变换,使得 A 变换为B。 现在的问题是:对于给定的A,B 及一组字串变换的规则,若A能在10步内(包含10步)变换成B,则输出所需的最短变换步数,否则输出NO ANSWER。 数据范围: 字串A,B长度小于等于20 规则总数小于等于6 输入格式: 从文件convert.in读入 第一行为两个字符串,第二行至文件尾为变换规则 变换规则一行为两个字符串A1 B1用空格分隔,表示 A1 -> B1 A B A1 B1 A2 B2 ... ... 输出格式: 输出到convert.out中 当变换步数在10步(包含10步)内,那么输出这个数字 否则,输出”NO ANSWER" 特别提醒: 这道题目很像WordLadder,用BFS也更为方便。但是,Lab2的主题是递归,所以大家这道题目不允许用BFS,必须是递归形式的。 对于每个测试用例,时间限制为1秒,实在不行,2秒也能接受。 规则没有优先级,所有的规则都是平等的,没有优先顺序。 可能会同时出现 a -> b a -> c这样的规则,就是说a可以转换成b,也可以转换成c。 问题二 24点 描述: 几十年前全世界流行一种叫作“算24点”数字扑克游戏。作为游戏者将得到4个1-13(在扑克牌里用A代替1,J代替11,Q代替12,K代替13)之间的自然数作为操作数,并对这四个数进行适当的算术运算(加,减,乘,除)使得最后结果为24。 例如: 4个数字为3 8 10 Q 那么一个方案可以是Q * ( 10 / ( 8-3 ) ) = 24 现在你的任务是实现一个自动24点计算器,对于任意的4个1-13的自然数,如果可以算出24点则输出一个合理方案,若无解则输出“NO ANSWER”。 数据范围: 4个数字属于S={1,2,3,4,5,6,7,8,9,10,J,Q,K} J,Q,K为字符 输入格式: 从文件calculator.in读入 一行4个数字,以空格分隔 输出格式: 输出到文件calculator.out中 一个字符串,表示最后的运算方案,符号与数字之间、符号与符号之间用空格分隔 如Q * ( 10 / ( 8 - 3 ) ) = 24 (Q与*之间有空格,(与10之间有空格) 或者当没有可行方案时输出“NO ANSWER"。 特别提醒: 这道题目还是用递归。 表达式中的每个子表达式的结果可以是小数,即例如 (3+3/7)*7=24 是合法的。 去除多余的括号。例如,对于2 2 3 8 这四个数字,一个解可以是3 * ( ( 8 + 2 ) - 2 ),但是要求是去除多余的括号,即最后的结果应该是3 * ( 8 + 2 - 2)。就是说,可以不用的括号都要去掉。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值