[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;
}
时间: 2024-10-18 08:52:17

[24点计算器][C++版本]无聊拿去玩的相关文章

24点计算器的Javascript实现

前段时间小舅子(小学生)过来玩,没事一起玩3*8=24,遇到难算的半天都想不出来,所以就想有没有app或者小工具啥的,搜了一下,有工具,但是不好用,所以就想自己写个简单易用的. 开始着手做的时候,发现运算逻辑无法总结成简单的计算公式,百度也没找到有人完整的实现,最后只能用最笨的方法了,且听我娓娓道来. 首先,按照常规,共有四个正整数参与运算,取值区间均为 [1,10](包含1和10),仅有加减乘除以及括号运算,不存在其他高级运算(如平方.开方等等),这四个数的计算顺序不确定,每个数字参与且仅参与

初学IOS开发-简单的加法计算器swift版本

先看图,要先把Main.storyboard里面的大致画好 这里用到4个Label,2个Text Field和1个Button具体的看下图 然后这是ViewController.swift(也就是代码区),看图 附上代码(需要的自己复制粘贴很贴心吧): import UIKit class ViewController: UIViewController { @IBOutlet weak var textNumber1: UITextField! @IBOutlet weak var textN

Linux基础命令的操作(时间与日期,日历,计算器)

时间与日期 如果想知道Linux系统的当前时间,使用 date 命令即可显示. 上图显示的时间是2017年01月24日,星期二,18点50分26秒.CST为时区缩写(China Standard Time)表示中国的标准时间. 如果希望只显示年月日可以通过命令 date +%Y/%m/%d 当然,如果只想知道现在几点了,可以使用命令 date +%H:%M:%S 单独将时分秒显示出来 日历 如果想看这个月的日历,可以使用 cal 命令查看. 上图显示了2017年1月份的日历,并高亮显示出了今天的

Java_计算器001,支持加减乘除,括号运算

暑假自学Java期间,为了练习Java编写的计算器001版本 1 import java.util.ArrayList; 2 //v1.0支持+-*/,负号 3 import java.util.Scanner; 4 public class Caculator_001 5 { 6 public static void main(String[] args) 7 { 8 Scanner input=new Scanner(System.in); 9 double result; 10 Strin

【每天学点Python】案例三:BMR计算器

BMR计算器 V1.0 案例描述: 基础代谢率(Basal Metabolic Rate,简称BMR)是指:我们在安静状态下(通常为静卧状态)消耗的最低热量,人的其他活动都建立在这个基础上 计算公式: BMR(男)=(13.7*体重(Kg))+(5.0*身高(cm))-(6.8*年龄)+ 66 BMR(女)=(9.6*体重(Kg))+(1.8*身高(公分))-(4.7*年龄)+ 655 案例分析: 输入: 性别: 体重: 身高: 体重 上机实验: 1 """ 2 作者:王鑫正

【实战学习c#】为程序设置版本和帮助信息

1实战说明 我们常在使用一款计算机软件的时候,能够看到其版本.公司及著作人等信息.如下图1所示.那我们应该如何设置软件的版本和帮助信息呢?我们以Visual Studio 2015 为例进行演示. 2预备知识 软件的信息主要在AssemblyInfo.cs中设置程序集. 2.1 通过代码配置AssemblyInfo文件 .net工程的Properties文件夹下自动生成一个名为AssemblyInfo.cs的文件,内部包含了一些属性标记,如版本信息等.一般情况下我们很少直接改动该文件. 单击后会

Fedora 24 Beta 版发布下载!

Fedora 24 Beta 在经过三次延期后终于在 2016 年 5 月 10 日放出,除了对传统 32 位和 64 位架构的支持外,此次 Fedora 24 Beta 还额外增加了对 PPC64.PPC64el 和 ARM64 的支持.此外,你还可以下载和测试基于云和 Docker 的 Beta 映像.为了满足不同的测试环境和特定用例,此次的测试版主要发布了 Fedora 24 Cloud Beta.Fedora 24 Server Beta 和 Fedora 24 Workstation

0414-复利计算器6.0.Release

复利计算器6.0--Release 前言 本次复利计算器的版本更新,主要有以下内容的完善: 1.优化了Web版的页面,提供了更舒服美观的用户体现. 2.新增了移动端(安卓)app版本. 版本信息 项目名称 复利计算器 项目版本 6.0 开发人员 曹嘉琪.梁植淋 开发工具 MySQL.Myeclipse.Android studio 使用JDK版本 1.7 最近更新 2016年4月14日 搭档博客地址推送:曹嘉琪的博客 分工与合作: 分工:梁植淋:主要负责安卓版复利计算器的编写. 曹嘉琪:主要负责

sdk 与adt不适用,在eclipse 中删除版本再装引起的问题

eclipse 使用的是4.3版本的,sdk 使用24.3.2,这里的是一个全量包来的,就是从24.3.2 以下的版本都包括在里面了,而 adt 只找到最高 23.06 一开始还能用着,但是,因版本不对称,总是要在里面降低sdk的版本,很麻烦,就想着直接在eclipse 里面运行SDK Manager 将 24.3.2  的版本文件删除,留下23.0.2那些,但是,在里面删了24.3.2 后,再去行eclipse 后就出错了,说没有了sdk文件什么的了,于是就再下载一个只有 23.0.2 版本的