[24点计算器][C++版本]无聊拿去玩

Posted Gster

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了[24点计算器][C++版本]无聊拿去玩相关的知识,希望对你有一定的参考价值。

程序用法:

  输入n,tar,lim;分别表示n个数,目标答案,最多计算lim个解(0表示输出所有解)

  然后输入n个数字

  例:  4 24 3

      1 2 3 4

      表示4个数字1,2,3,4要算出24的前三个解

      一般6个数找所有答案开O2需要一分半吧。。

 

思路(当然是爆枚咯。。。)

由于中缀表达式枚举括号比较麻烦,所以用后缀表达式枚举运算符,最后再把后缀转成中缀输出即可。

但这样还枚举不全,需要枚举数字的全排列再把运算符填进去。

这样虽然可以枚举所有情况,但是因为交换律的存在大量重复出现(比如2*3*4  3*2*4...)所以要去重。。

由于本人能力有限,,所以用了奇怪的方法,,不过效果还不错,方法如下。

  随机生成若干个(程序里是4个)数组,和原数组匹配,然后用同样的运算符计算各个数组,把答案打包存进map有重复不输出即可

  例:

    比如当前枚举的运算方法是(a+b)/c*d

    原数组:

      w  x  y  z    ==>(w+x)/y*z

    随机数组:

      a[0][0] a[0][1] a[0][2] a[0][3]   ==>(a[0][0]+a[0][1])/a[0][2]*a[0][3]=A

      a[1][0] a[1][1] a[1][2] a[1][3]   ==>(a[1][0]+a[1][1])/a[1][2]*a[1][3]=B

      a[2][0] a[2][1] a[2][2] a[2][3]   ==>(a[2][0]+a[2][1])/a[2][2]*a[2][3]=C

      ......

      把{A,B,C,....}放到map里

    当枚举到(b+a)/c*d的时候发现

      x      w  y  z    ==>(x+w)/y*z

      a[0][1] a[0][0] a[0][2] a[0][3]   ==>(a[0][1]+a[0][0])/a[0][2]*a[0][3]=D

      a[1][1] a[1][0] a[1][2] a[1][3]   ==>(a[1][1]+a[1][0])/a[1][2]*a[1][3]=E

      a[2][1] a[2][0] a[2][2] a[2][3]   ==>(a[2][1]+a[2][0])/a[2][2]*a[2][3]=F

       此时{A,B,C,...}=={D,E,F,...}说明(a+b)/c*d和(b+a)/c*d是同样的表达式,那么不输出即可。

 

  代码如下(后缀转中缀不会写啊。。捂脸。网上扒了一篇。。)

  

#include <bits/stdc++.h>

using namespace std;

const int base=10;

int    n,a[100],vec[100],tar,trw=1,Cnt;
int    test[100][4],testb[100][4];
bool    visited[100];

//==============EXCHANGE==============
namespace EXCHANGE
{
    int JudgePriority(char c);
    int Length;
    class StringNode
    {
        private:
        string STring;
        int priority;
        public:
        StringNode() { priority = 10; }
        StringNode(char Char1) { STring = Char1; priority = 4; }
        StringNode(string ExpressionString, int Priority1)
        { STring = ExpressionString; priority = Priority1; }
        friend StringNode Compose(StringNode &SN1,
            char Operator, StringNode &SN2)
        {
            AutoAddBrackets(SN1, Operator, SN2);
            return StringNode(SN1.STring + Operator + SN2.STring,
                    JudgePriority(Operator));
        }
        friend StringNode Compose(StringNode &SN1, char Operator)
        {
            AutoAddBrackets(SN1);
            SN1.STring += Operator;
            return StringNode(SN1.STring, 3);
        }
        friend void AutoAddBrackets(StringNode &SN1,
                char Operator, StringNode &SN2)
        {
            if (SN1.priority >= JudgePriority(Operator) &&
              JudgePriority(Operator) >= SN2.priority)
                { SN2.AddBrackets(); return; }
            else if (SN1.priority == 1 &&
              (Operator==*|| Operator == /) &&
                SN2.priority >= 3)
                { SN1.AddBrackets(); return; }
            else if (SN1.priority == 1 && 
              (Operator == * || Operator == /) &&
                SN2.priority <= 2)
            { SN1.AddBrackets(); SN2.AddBrackets(); return; }
            else return;
        }
        friend void AutoAddBrackets(StringNode &SN1)
        { if (SN1.priority<3 ) { SN1.AddBrackets(); } }
        void AddBrackets()
        { STring =  STring.insert(0,1,() + ")"; priority = 4; }
        void PrintString() { cout << STring; }
        string    ReturnString() { return STring; }
    };

    class Stack
    {
        private:
        StringNode *Buffer; int top;
        public:
        Stack(int Len) { Buffer = new StringNode[Len]; top = 0; }
        void push(StringNode val) { Buffer[top++] = val; }
        StringNode pop() { top--; return Buffer[top]; }
        void PrintStack() { Buffer[0].PrintString(); }
        string    ReturnString() { return Buffer[0].ReturnString(); }
    };

    bool IsCharacter(char c) { return c >= a&&c <= z; }
    bool IsBiOperator(char c) { return c==+||c==*||c==/||c==-; }
    bool IsSingleOperator(char c) { return c == !; }
    int JudgePriority(char c)
    { if (c == + || c == -) return 1;
      else if (c == * || c == /) return 2;
        else if (c == !) return 3; else return 10; }

    string work(string Str)
    {
        int c = 0; Length = Str.size();
        Stack StackObject(Length);
        while (c < (int)Str.size())
        {
            if (IsCharacter(Str.at(c)))
            { StackObject.push(StringNode(Str.at(c))); }
            else if (IsBiOperator(Str.at(c)))
            {
                StringNode TempSN1 = StackObject.pop();
                StringNode TempSN2 = StackObject.pop();
                StackObject.push
                (Compose(TempSN2, Str.at(c), TempSN1));
            }
            else if (IsSingleOperator(Str.at(c)))
            {
                StringNode TempSN = StackObject.pop();
                StackObject.push
                    (Compose(TempSN,Str.at(c)));
            } c++;
        }
        return StackObject.ReturnString();
    }
}
//=============EXCHANGE==END============

struct T
{
    double    aa,bb,cc,dd;
    bool    operator<(const T temp)const
    {
        if(fabs(aa-temp.aa)>1e-3) return aa<temp.aa;
        if(fabs(bb-temp.bb)>1e-3) return bb<temp.bb;
        if(fabs(cc-temp.cc)>1e-3) return cc<temp.cc;
        if(fabs(dd-temp.dd)>1e-3) return dd<temp.dd;
        return false;
    }
};


vector<int>    op[100];
map<T,bool> Map;

void    Init_random_list()
{
    srand(time(0));
    for(int j=0;j<4;++j) for(int i=0;i<n;++i) test[i][j]=rand()%(base*10);
    for(int i=0;i<n;++i) for(int j=i+1;j<n;++j)
    if(a[i]==a[j]) for(int k=0;k<4;++k) test[j][k]=test[i][k];
    return ;
}
double    C()
{
    stack<double>    S;
    stack<double>    r[4];
    for(int i=0;i<n;++i)
    {
        S.push(vec[i]);
        for(int j=0;j<(int)op[i].size();++j)
        {
            double t1=S.top(); S.pop();
            double t2=S.top(); S.pop();
            if(op[i][j]==0) S.push(t2+t1);
            if(op[i][j]==1) S.push(t2-t1);
            if(op[i][j]==2) S.push(t2*t1);
            if(op[i][j]==3) S.push(t2/t1);
        }
    }
    if(fabs(S.top()-(double)tar)<1e-8)
    {
        for(int i=0;i<n;++i)
        {
            for(int k=0;k<4;++k)
            {
                r[k].push(testb[i][k]);
                for(int j=0;j<(int)op[i].size();++j)
                {
                    double t1=r[k].top(); r[k].pop();
                    double t2=r[k].top(); r[k].pop();
                    if(op[i][j]==0) r[k].push(t2+t1);
                    if(op[i][j]==1) r[k].push(t2-t1);
                    if(op[i][j]==2) r[k].push(t2*t1);
                    if(op[i][j]==3) r[k].push(t2/t1);
                }
            }
        }
        T temp=(T){r[0].top(),r[1].top(),r[2].top(),r[3].top()};
        if(Map[temp])return -1e100;
        Map[temp]=true;
    }
    return S.top();
}

void    Pr()
{
    Cnt++; string    str;
    for(int i=0;i<n;++i)
    {
        str+=a+i;
        for(int j=0;j<(int)op[i].size();++j)
        {
            if(op[i][j]==0) str+=+;
            if(op[i][j]==1) str+=-;
            if(op[i][j]==2) str+=*;
            if(op[i][j]==3) str+=/;
        }
    }
    //str是后缀表达式,vec里存的是当前数字的顺序,改下面输出后缀表达式会比较整齐
    int t=0; str=EXCHANGE::work(str);
    for(int i=0;i<(int)str.size();++i)
    {
        if(str[i]>=a && str[i]<=z) printf("%d ",vec[t++]);
        else    printf("%c ",str[i]);
    }
    printf("\n");
    return ;
}

/* Violent enumeration operator */
void    Calc(const int step,const int pos,const int lim)
{
    if(step==n-1) 
    {
        if(fabs(C()-(double)tar)<1e-8)
        {
            Pr();
            if(Cnt==trw)throw 0;
        }
        return ;
    }
    for(int i=pos;i<n;++i)
    {
        for(int j=0;j<=lim;++j)
        {
            op[i].push_back(j);
            if(step+1<=i) Calc(step+1,i,lim);
            op[i].pop_back();
        }
    }
    return ;
}

/* Violent enumeration Permutations */
void    Dfs(const int step,const int lim)
{
    if(step==n)
    {
        try{Calc(0,0,lim);}
        catch(...){throw 0;}
        return ;
    }
    for(int i=0;i<n;++i)
    {
        if(!visited[i])
        {
            visited[i]=true;
            vec[step]=a[i];
            for(int j=0;j<4;++j)
                testb[step][j]=test[i][j];
            Dfs(step+1,lim);
            visited[i]=false;
        }
    }
    return ;
}

int main()
{
    printf("Size of Input:\t"); scanf("%d",&n);
    printf("Target Result:\t"); scanf("%d",&tar);
    printf("Result limits(0 for no limits):  "); scanf("%d",&trw);

    printf("Input(32bits integers):\n");
    for(int i=0;i<n;++i) scanf("%d",&a[i]);

    Init_random_list();

    printf("========================\n");
    //这里会优先选择没有乘除的方案
    try{Dfs(0,0);}catch(...){}
    try{Dfs(0,1);}catch(...){}
    try{Dfs(0,2);}catch(...){}
    try{Dfs(0,3);}catch(...){}
    printf("========================\n");

    printf("%d Results Found!\n",Cnt);
    return 0;
}

 

以上是关于[24点计算器][C++版本]无聊拿去玩的主要内容,如果未能解决你的问题,请参考以下文章

生活这么无聊,保存点小姐姐的图片来点调料吧

利用c++ 做二十四点游戏。请高手们帮忙!谢谢

c++多线程编程:实现标准库accumulate函数的并行计算版本

point24 c++

网络流24题餐巾计划问题(最小费用最大流)

python实现24点游戏(地球上最短的24点游戏代码?)