• 24点游戏算法


    游戏规则: 一副牌中去掉大小王,在剩下的52张牌中任意取四张。使用四则运算,使其最后结果为24.其中每张牌只能使用一次且A=1,J=11,Q=12,K=13。

         譬如 2,4,6,8  ------>  结果为 6/(4-2)*8=24;

    算法思考: 首先,从宏观上说,这种问题都是遍历穷举。再看看运算符,其中+,* 都是没有顺序的。即(a*b=b*a), 但是 -、/ 是有顺序的。那么假设都有顺序的。那么就可以统一处理了(最多效率低点,先解决问题。再考虑优化)。那么遍历所有a,b,c,d 以及 三次运算 。即A(4,4) *4*4*4 就是该算法的复杂度。(事实证明我错了。后面会讲到。)

         微观上,由于中间有除法,那么不能用int类型来储存数据了。需要用double或者float.每次运算都只有两个数运算。我们可用 Function CalcValue(float x,float y , char sy)来表示。x表示第一数,y表示第二个数, sy表示四则运算符之一。

      代码如下:

    View Code
            public float CalcValue(float x, float y, char f)
    {
    float res = 0;
    switch (f)
    {
    case '+': res = x + y;
    break;
    case '-': res = x - y;
    break;
    case '*': res = x * y;
    break;
    case '/': res = x / y;
    break;
    default:
    break;
    }
    return res;
    }

      遍历代码如下

    View Code
    for (int i1 = 0; i1 < Nums.Count; i1++)//Nums 为4个数   
    {
    List<float> Nums1 = CloneValue(this.Nums);
    float num1 = Nums1[i1];//第一个数
    Nums1.RemoveAt(i1);//移除第一数

    for (int i2 = 0; i2 < Nums1.Count; i2++)//遍历剩下的3个数
    {
    List<float> Nums2 = CloneValue(Nums1);
    float num2 = Nums1[i2];//第二个数
    Nums2.RemoveAt(i2);

    for (int i3 = 0; i3 < Nums2.Count; i3++)
    {
    List<float> Nums3 = CloneValue(Nums2);
    float num3 = Nums2[i3];//第三个数
    Nums3.RemoveAt(i3);

    //第四个数,因为最后一个了。不要循环了。
    float num4 = Nums3.First();

    //即四个数的顺序为num4,num3,num2,num1;接下来遍历符号

    for (int sy1 = 0; sy1 < 4; sy1++)//遍历第一的运算符号
    {
    char currentSymbol1 = symbols[sy1];
    float tem1 = CalcValue(num4, num3, currentSymbol1);//第一个中间值

    for (int sy2 = 0; sy2 < 4; sy2++)
    {
    char currentSymbol2 = symbols[sy2];

    float tem2 = 0;
    for (int dir = 0; dir < 2; dir++)//一开始没写这个循环。只计算了下面注释的部分。其实写程序到这里我就感觉不太对了。。后来验证果然不对。
    {
    if (dir == 0)
    {
    tem2 = CalcValue(tem1, num2, currentSymbol2);
    }
    if (dir == 1)
    {
    tem2 = CalcValue(num2, tem1, currentSymbol2);
    }
    // float tem2 = CalcValue(tem1, num2, currentSymbol2);
    for (int sy3 = 0; sy3 < 4; sy3++)
    {
    char currentSymbol3 = symbols[sy3];
    float tem3 = 0;
    for (int dir2 = 0; dir2 < 2; dir2++)//同样。这个一开始没写。后来补的。
    {
    if (dir2 == 0)
    {
    tem3 = CalcValue(tem2, num1, currentSymbol3);
    }
    if (dir2 == 1)
    {
    tem3 = CalcValue(num1, tem2, currentSymbol3);
    }
    // float tem3 = CalcValue(tem2, num1, currentSymbol3);

    if (tem3 == 24)//发现了计算
    {
    //下面的都是后来补的。所以导致程序很乱。
    if (dir == 0 && dir2==0)//按顺序的
    {
    Console.WriteLine("{0}{1}{2}, {3}{4},{5}{6}", num4, currentSymbol1, num3, currentSymbol2, num2, currentSymbol3, num1);
    }
    if (dir == 1 && dir2==0)//第二次计算时 num2与temp四则运算 如 6/(4-2) * 8
    {
    Console.WriteLine("{3}{4},{0}{1}{2},{5}{6}", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
    }
    if (dir==0 && dir2 == 1)// 最后次计算 num4与temp四则运算 如 4/(1-5/6)
    {
    Console.WriteLine("{6}{5}, ({0}{1}{2},{4}{3})", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
    }
    if (dir==1 && dir2 == 1)// 如 8/(3-8/3)
    {
    Console.WriteLine("{6}{5}, {4}{3},{0}{1}{2}", num4, currentSymbol1, num3, num2, currentSymbol2, currentSymbol3, num1);
    }
    return;
    }
    }//---

    }

    }//---
    }
    }
    }
    }



    }

      从遍历代码中发现。我们少考虑的点东西。 即并不是遍历所有abcd以及 运算的组合就行了。我们遍历的只是数出现的顺序。而并没有遍历所有表达式。

    举个例子: ((a+b)-c)+d 和 (c-(a+b))+d  这两个表达式 都是 ab运算, 再和c运算,最后和d运算。 运算数的顺序是一样的,都是abcd,但是表达式不同。

    也就是说,遍历数所有abcd的组合还不够。还需要添加一个顺序。计算的顺序。于是在遍历的程序中 多了两个for(dir=0;dir<2;dir++) 的循环。。。

    重新思考:  看到计算表达式 ((a+b)-c)+d  ,就想起大学时候的波兰表达式。 先去括号再说。ab+c-d+。很好很强大!!这个就能解决顺序的问题。不必先弄所有的数字的组合(带顺序的,A(x,x),不是C(x,x) ) 然后还要考虑 计算的顺序。。。。那么关键是有多少种符合的表达式类型呢? 穷举!!!

    改天再想吧。。。

    罗列下待解决的问题: 效率问题。太多的重复判断。或许波兰表达式能解决。

               去括号后相同的表达式。。 譬如 a-(b+c)+d  与 a-b-c+d  是相同的。




  • 相关阅读:
    人工智能应用卷积神经网络对食道癌的诊断结果--笔记
    面向对象设计
    结构化软件测试----白盒测试技术
    内聚与耦合的实例分析
    图书预定系统
    SQL小技巧
    Keras中RNN、LSTM和GRU的参数计算
    Keras+Tensorboard
    Floyd算法
    生成随机整数
  • 原文地址:https://www.cnblogs.com/xinjian/p/2221544.html
Copyright © 2020-2023  润新知