一个类24点问题算法实现

问题描述:
   在game.in中给定任意5个整数和期望数EXPECTION_VAL,使用+ - * /进行对这5个数进行运算,每个运算操作只能使用一次,()可以使用无数次。
   输出一个计算结果或者证明无合适解。

算法思路:
  一个基本的解析算式是exp = (exp | num ) op (exp | num)
  接下来使用动态规划进行计算就行了,将最近操作的两个数加入到算子集合重新计算,如此递归,直至找到解或者计算完所有的可能。
  对于calculate函数相关的因素包括(算子集合,操作子集合)。
  递归边界应该是算子集合数目为2并且操作子数目为1。

说明:
  本程序的实现没有怎么优化,有很多冗余可以使用记录exp算式的方法进行剔除,  
/*******************************************************************************
 * created:2012/04/26
 * created:2012-4-26   11:04
 * file base:main
 * file ext:cpp
 * author:xiaoyang hityixiaoyang@gmail.com
********************************************************************************
 * 描述:
 * 在game.in中给定任意5个整数和期望数EXPECTION_VAL,使用+ - * /进行对这5
 * 个数进行运算,每个运算操作只能使用一次,()可以使用无数次。
 * 输出一个计算结果或者证明无合适解。
********************************************************************************/
#include <iostream>
#include <vector>
#include <fstream>
#include <algorithm>
#include <string>
#include <stack>

using namespace std;

long CalCount = 0;

const char* INPUT_FILE  = "game.in";
const char* OUTPUT_FILE = "game.out";
const char* RES_FILE = "game.res";
const int NUMBER_COUNT  = 5;
//const 
int EXPECTION_VAL = 0;

vector<int> Nums;
//vector<int> OrgNums;
vector<char> Ops;
//vector<char> OrgOps;
ofstream fout;
ofstream fres;
typedef struct exp {
    int num1;
    int num2;
    char op;
} Exp;
stack<exp> ResStr;

void PrintRes()
{
    fout<< "--------------------" <<endl;
    fres<< "--------------------" <<endl;
    while (!ResStr.empty()) {
        fout << ResStr.top().num1  << ","  << ResStr.top().num2 << "," << ResStr.top().op << endl;
        fres << ResStr.top().num1  << ","  << ResStr.top().num2 << "," << ResStr.top().op << endl;
        ResStr.pop();
    }
    fout<< "--------------------\nend!" <<endl;
    fres <<endl;
}

void AddRes(int num1,int num2, char op)
{
    Exp tmpExp;
    tmpExp.num1 = num1;
    tmpExp.num2 = num2;
    tmpExp.op = op;
    ResStr.push(tmpExp);
}

void Config()
{
    int tmp = 0;
    ifstream fin(INPUT_FILE);
    if (fin.eof()) {
        exit(-2);
    }

    for (int i = 0; i < NUMBER_COUNT; i++) {
        fin >> tmp;
        Nums.push_back(tmp);
    }

    fin >> EXPECTION_VAL;
    Ops.push_back('+');
    Ops.push_back('-');
    Ops.push_back('*');
    Ops.push_back('/');

    fout.open(OUTPUT_FILE);
    fout << "steps:"<<endl;

    fres.open(RES_FILE);
    fres << "steps:"<<endl;
}


/*
 * ret:
 *        -1,calculate failed
 *        0,success
 */
int Calculate(vector<int>& iNums,vector<char>& iOps)
{
    //unsigned int i=0, j=0, k=0;
    int newNum1 = 0, newNum2 = 0;
    vector<char>::iterator vc_it;

    /**/
    if ((iOps.size() == 1) || (iNums.size() == 2)) {
        int res = -1;
        if (iOps[0] == '+') {
            res = iNums[0] + iNums[1];
            /*(n,n,op) res:*/
            fout << "(" << iNums[0] << "," << iNums[1] << "," << iOps[0] << ") res:" << res << endl;
            if(res == EXPECTION_VAL) {
                goto suc;
            } else {
                goto fail;
            }
        } else if (iOps[0] == '-') {
            res = iNums[0] - iNums[1];
            /*(n,n,op) res:*/
            fout << "(" << iNums[0] << "," << iNums[1] << "," << iOps[0] << ") res:" << res << endl;
            if(res == EXPECTION_VAL) {
                goto suc;
            } else {
                fout << "failed:recalculate!" << endl;
            }

            res = iNums[1] - iNums[0];
            /*(n,n,op) res:*/
            fout << "(" << iNums[1] << "," << iNums[0] << "," << iOps[0] << ") res:" << res << endl;
            if(res == EXPECTION_VAL) {
                goto suc;
            } else {
                goto fail;
            }
        } else if (iOps[0] == '*') {
            res = iNums[0] * iNums[1];
            /*(n,n,op) res:*/
            fout << "(" << iNums[0] << "," << iNums[1] << "," << iOps[0] << ") res:" << res << endl;
            if(res == EXPECTION_VAL) {
                goto suc;
            } else {
                goto fail;
            }
        } else if (iOps[0] == '/') {
            if((iNums[0] == 0) | (iNums[1] == 0)) {
                res = 0;
                fout << "(" << iNums[0] << "," << iNums[1] << "," << iOps[0] << ") res:" << res << endl;
                if(res == EXPECTION_VAL) {
                    goto suc;
                } else {
                    goto fail;
                }
            } else {
                res = (int)(iNums[0] / iNums[1]);
                fout << "(" << iNums[0] << "," << iNums[1] << "," << iOps[0] << ") res:" << res << endl;
                if(res == EXPECTION_VAL) {
                    goto suc;
                } else {
                    fout << "failed:recalculate!" << endl;
                }

                res = (int)(iNums[1] / iNums[0]);
                fout << "(" << iNums[1] << "," << iNums[0] << "," << iOps[0] << ") res:" << res << endl;
                if(res == EXPECTION_VAL) {
                    goto suc;
                } else {
                    goto fail;
                }
            }
        } else {
            cout << "error: unknown exception @"<< __LINE__ << endl;
            return -1;
        }

suc:
        CalCount++;
        return 0;
fail:
        fout << "failed:recalculate!" << endl;
        CalCount++;
        return -1;
    }


    /*it's important!used for resume stack*/
    vector<int> OrgNums(iNums);
    vector<char> OrgOps(iOps);
    /*choose 2 numbers,calculate them*/
    for (unsigned int i = 0; i < OrgNums.size(); i++) {
        newNum1 = iNums.at(i);
        iNums.erase(iNums.begin()+i);
        
        /*it's important!used for resume stack*/
        vector<int> OrgNums2(iNums);
        for(unsigned int j = 0; j < iNums.size(); j++) {
            newNum2 = iNums.at(j);
            iNums.erase(iNums.begin()+j);

            fout << "\t" << newNum1 << "," << newNum2 <<endl;
            /*+*/
            vc_it = find(iOps.begin(),iOps.end(),'+');
            if(vc_it != iOps.end()) {
                fout << "(" << newNum1 << "," << newNum2 << ",+)" << endl;
                iNums.push_back(newNum1+newNum2);
                iOps.erase(vc_it);
                if (Calculate(iNums,iOps) == 0) {
                    AddRes(newNum1,newNum2,'+');
                    cout << "success:got it!" << endl;
                    fout << "success:got it!" << endl;
                    return 0;
                } else {
                    iNums.pop_back();
                    iOps.clear();
                    iOps = OrgOps;
                }
            }


            /*-*/
            vc_it = find(iOps.begin(),iOps.end(),'-');
            if(vc_it != iOps.end()) {
                fout << "(" << newNum1 << "," << newNum2 << ",-)" << endl;
                iNums.push_back(newNum1-newNum2);
                iOps.erase(vc_it);
                if (Calculate(iNums,iOps) == 0) {
                    AddRes(newNum1,newNum2,'-');
                    cout << "success:got it!" << endl;
                    fout << "success:got it!" << endl;
                    return 0;
                } else {
                    iNums.pop_back();
                    iOps.clear();
                    iOps = OrgOps;
                }

                fout << "(" << newNum2 << "," << newNum1 << ",-)" << endl;
                vc_it = find(iOps.begin(),iOps.end(),'-');
                if(vc_it != iOps.end()) {
                    iNums.push_back(newNum2-newNum1);
                    iOps.erase(vc_it);
                    if (Calculate(iNums,iOps) == 0) {
                        AddRes(newNum2,newNum1,'-');
                        cout << "success:got it!" << endl;
                        fout << "success:got it!" << endl;
                        return 0;
                    } else {
                        iNums.pop_back();
                        iOps.clear();
                        iOps = OrgOps;
                    }
                }
            }

            /***/
            vc_it = find(iOps.begin(),iOps.end(),'*');
            if(vc_it != iOps.end()) {
                fout << "(" << newNum1 << "," << newNum2 << ",*)" << endl;
                iNums.push_back(newNum1*newNum2);
                iOps.erase(vc_it);
                if (Calculate(iNums,iOps) == 0) {
                    AddRes(newNum1,newNum2,'*');
                    cout << "success:got it!" << endl;
                    fout << "success:got it!" << endl;
                    return 0;
                } else {
                    iNums.pop_back();
                    iOps.clear();
                    iOps = OrgOps;
                }
            }


            /*/*/
            vc_it = find(iOps.begin(),iOps.end(),'/');
            if(vc_it != iOps.end()) {
                if (newNum2 != 0) {
                    fout << "(" << newNum1 << "," << newNum2 << ",/)" << endl;
                    if (newNum1%newNum2 == 0) {
                        iNums.push_back((int)(newNum1/newNum2));
                        iOps.erase(vc_it);
                        if (Calculate(iNums,iOps) == 0) {
                            AddRes(newNum1,newNum2,'/');
                            cout << "success:got it!" << endl;
                            fout << "success:got it!" << endl;
                            return 0;
                        } else {
                            iNums.pop_back();
                            iOps.clear();
                            iOps = OrgOps;
                        }
                    }
                }

                vc_it = find(iOps.begin(),iOps.end(),'/');
                if(vc_it != iOps.end()) {
                    if (newNum1 != 0) {
                        if (newNum2%newNum1 == 0) {
                            fout << "(" << newNum2 << "," << newNum1 << ",/)" << endl;
                            iNums.push_back((int)(newNum2/newNum1));
                            iOps.erase(vc_it);
                            if (Calculate(iNums,iOps) == 0) {
                                AddRes(newNum2,newNum1,'/');
                                cout << "success:got it!" << endl;
                                fout << "success:got it!" << endl;
                                return 0;
                            } else {
                                iNums.pop_back();
                                iOps.clear();
                                iOps = OrgOps;
                            }
                        }
                    }
                }
            }


            iNums.clear();
            iNums = OrgNums2;
        }

       

        iNums.clear();
        iNums = OrgNums;
    }

   
    //iOps = OrgOps;
    /*no res*/
    cout << "no answer!" << endl;
    fout << "no answer!" << endl;

    return -1;
}

int main(void)
{
    Config();
    Calculate(Nums,Ops);
    PrintRes();
    cout << "Calculate times:" << CalCount << endl;
    fout << "Calculate times:" << CalCount << endl;
    fres << "Calculate times:" << CalCount << endl;
    fout.flush();
    fres.flush();
    getchar();
    return 0;
}

使用这个代码前需要先家建立1个输入文件game.in,并在文件里输入5个算子和一个期望值。

输出结果会在game.res、 game.out文件中显示

原文地址:https://www.cnblogs.com/yixiaoyang/p/2471096.html