经典游戏--24点--c++代码实现和总体思路(简单暴力向)

24点

  24点是一个非常经典的游戏,从扑克牌里抽4张牌,其中J=11,Q=12,K=13,然后经过+,-,*,/,(),的计算后,使得计算得值为24,例如抽到1,2,2,5四张牌,那么

  (1+5)*(2+2)=24;

  这就是可以凑成24点的一种情况,作为一个经典题目,在leetcode上也有对应的题目进行练习

  PS 看见知乎大佬有一种必24点的算法,但是要用到阶乘和次方 式子为(a0+b0+c0+d0)! =24

一、总体思路

  1.因为是简单暴力向的,所以我们的做法就是直接穷举出所有可能的情况,首先是考虑四个数a,b,c,d的排列情况

    如b,a,c,d等等,通过排列组合可以得到 4*3*2*1 = 24 种情况

  2.然后考虑a,b,c,d中的三个运算符的情况设一个自定义的运算符为$,$可以是+,-,*,/中的任意一个

    则有 a$b$c$d 这个式子,同样,运算符的可能性有 3*4 = 12 种

  3.最后考虑()的情况,我们规定,每次一对()只框住两个数,比如a+b+c+d =(((a+b)+c)+d) = ((r1+c)+d)=(r2+d)=r3(其中r1=a+b,r2=r1+c,r3=r2+d)

    ()的情况其实就是运算优先级的问题,无论运算符是什么,都一定是先运算括号里的内容

    所以我们可以穷举出情况

    第一种r1=a$b,r2=r1$c,r3=r2$d;

    第二种r1=b$c,r2=a$r1,r3=r2$d;

    第三种r1=b$c,r2=r1$d,r3=a$r2;

    第四种r1=c$d,r2=b$r1,r3=a$r2;

    第五种r1=a$b,r2=c$d,r3=r1$r2;

  仔细观察不难发现,我们控制了运算符和数字的绝对顺序从左到右的顺序严格是a$b$c$d,不论任何情况都不会改变abcd的顺序,是因为我们在上面已经排出来了所有的24种情况,所以我们这就可以严格控制abcd的顺序了

二、代码实现

  1 #include <iostream>
  2 #include <string>
  3 using namespace std;
  4 int mark_int[4] = { 1,2,3,4 };
  5 string mark_char = "+-*/";
  6 double cal(double a, int m, double b)
  7 {
  8     switch (m)
  9     {
 10     case 1:    return a + b;
 11     case 2:    return a - b;
 12     case 3:    return a * b;
 13     case 4:    return a / b;
 14     }
 15 }
 16 
 17 bool cal1(double a, double b, double c, double d, int m1, int m2, int m3)
 18 {
 19     double r1;
 20     double r2;
 21     double r3;
 22     r1 = cal(a, m1, b);
 23     r2 = cal(r1, m2, c);
 24     r3 = cal(r2, m3, d);
 25     if (r3 == 24)
 26     {
 27         cout << "(((" << a << mark_char[m1 - 1] << b << ")" << mark_char[m2 - 1] << c << ")" << mark_char[m3 - 1] << d << ")" << endl;
 28         return 1;
 29     }
 30     return 0;
 31 }
 32 
 33 bool cal2(int a, int b, int c, int d, int m1, int m2, int m3)
 34 {
 35     double r1;
 36     double r2;
 37     double r3;
 38     r1 = cal(b, m1, c);
 39     r2 = cal(a, m2, r1);
 40     r3 = cal(r2, m3, d);
 41     if (r3 == 24)
 42     {
 43         cout << "((" << a << mark_char[m1 - 1] << "(" << b << mark_char[m2 - 1] << c << "))" << mark_char[m3 - 1] << d << ")" << endl;
 44         return 1;
 45     }
 46     return 0;
 47 }
 48 
 49 bool cal3(int a, int b, int c, int d, int m1, int m2, int m3)
 50 {
 51     double r1;
 52     double r2;
 53     double r3;
 54     r1 = cal(b, m1, c);
 55     r2 = cal(r1, m2, d);
 56     r3 = cal(a, m3, r2);
 57     if (r3 == 24)
 58     {
 59         cout << "(" << a << mark_char[m1 - 1] << "((" << b << mark_char[m2 - 1] << c << ")" << mark_char[m3 - 1] << d << "))" << endl;
 60         return 1;
 61     }
 62     return 0;
 63 }
 64 
 65 bool cal4(int a, int b, int c, int d, int m1, int m2, int m3)
 66 {
 67     double r1;
 68     double r2;
 69     double r3;
 70     r1 = cal(c, m1, d);
 71     r2 = cal(b, m2, r1);
 72     r3 = cal(a, m3, r2);
 73     if (r3 == 24)
 74     {
 75         cout << "(" << a << mark_char[m1 - 1] << "(" << b << mark_char[m2 - 1] << "(" << c << mark_char[m3 - 1] << d << ")))" << endl;
 76         return 1;
 77     }
 78     return 0;
 79 }
 80 
 81 bool cal5(int a, int b, int c, int d, int m1, int m2, int m3)
 82 {
 83     double r1;
 84     double r2;
 85     double r3;
 86     r1 = cal(a, m1, b);
 87     r2 = cal(c, m3, d);
 88     r3 = cal(r1, m2, r2);
 89     if (r3 == 24)
 90     {
 91         cout << "((" << a << mark_char[m1 - 1] << b << ")" << mark_char[m2 - 1] << "(" << c << mark_char[m3 - 1] << d << "))" << endl;
 92         return 1;
 93     }
 94     return 0;
 95 }
 96 
 97 
 98 bool all_cal(int a, int b, int c, int d)
 99 {
100     for (int i = 1; i <= 4; i++)
101         for (int j = 1; j <= 4; j++)
102             for (int k = 1; k <= 4; k++)
103             {
104                 if (cal1(a, b, c, d, i, j, k) == true || cal2(a, b, c, d, i, j, k) == true || cal3(a, b, c, d, i, j, k) == true || cal4(a, b, c, d, i, j, k) == true || cal5(a, b, c, d, i, j, k) == true)
105                     return 1;
106             }
107     return 0;
108 }
109 
110 
111 bool judge(int a, int b, int c, int d)
112 {
113     int all[24][4] = {
114         {a,b,c,d},{a,b,d,c},{a,c,b,d},{a,c,d,b},{a,d,b,c},{a,d,c,b},
115         {b,a,c,d},{b,a,d,c},{b,c,a,d},{b,c,d,a},{b,d,a,c},{b,d,c,a},
116         {c,a,b,d},{c,a,d,b},{c,b,a,d},{c,b,d,a},{c,d,a,b},{c,d,b,a},
117         {d,a,b,d},{d,a,d,b},{d,b,a,c},{d,b,c,a},{d,c,a,b},{d,c,b,a},
118     };
119     for (int i = 0; i < 24; i++)
120     {
121         if (all_cal(all[i][0], all[i][1], all[i][2], all[i][3]))
122             return 1;
123     }
124     return 0;
125 }
126 
127 int main()
128 {
129     int a, b, c, d;
130     cin >> a >> b >> c >> d;
131     if (!judge(a, b, c, d))
132         cout << "凑不成24点" << endl;
133 
134 }

三、代码解释

先做一个计算两个数的函数,用数组int mark_int[4] = {1,2,3,4}的四个数表示+ - * /,string mark_char是用来最后显示的

 1 int mark_int[4] = { 1,2,3,4 };
 2 string mark_char = "+-*/";
 3 double cal(double a, int m, double b)
 4 {
 5     switch (m)//用switch来进行运算符的选择
 6     {
 7     case 1:    return a + b;
 8     case 2:    return a - b;
 9     case 3:    return a * b;
10     case 4:    return a / b;
11     }
12 }

我们在实现五种括号的函数,并且我们规定运算一定是 a m1 b m2 c m3 d(m1,m2,m3是三个运算符的代号),意思就是abcd的从左到右顺序不乱,m1m2m3从左到右的顺序也不会乱,比较粗暴的理解就是ab之间一定是m1,bc之间一定是m2,cd之间一定其实m3,然后如果成功返回运算的过程和true,否则返回false

 1 bool cal1(double a, double b, double c, double d, int m1, int m2, int m3)
 2 {
 3     double r1;
 4     double r2;
 5     double r3;
 6     r1 = cal(a, m1, b);
 7     r2 = cal(r1, m2, c);
 8     r3 = cal(r2, m3, d);
 9     if (r3 == 24)
10     {
11         cout << "(((" << a << mark_char[m1 - 1] << b << ")" << mark_char[m2 - 1] << c << ")" << mark_char[m3 - 1] << d << ")" << endl;
12         return 1;
13     }
14     return 0;
15 }//第一种r1=a$b,r2=r1$c,r3=r2$d;
16 
17 bool cal2(int a, int b, int c, int d, int m1, int m2, int m3)
18 {
19     double r1;
20     double r2;
21     double r3;
22     r1 = cal(b, m1, c);
23     r2 = cal(a, m2, r1);
24     r3 = cal(r2, m3, d);
25     if (r3 == 24)
26     {
27         cout << "((" << a << mark_char[m1 - 1] << "(" << b << mark_char[m2 - 1] << c << "))" << mark_char[m3 - 1] << d << ")" << endl;
28         return 1;
29     }
30     return 0;
31 }//第二种r1=b$c,r2=a$r1,r3=r2$d;
32 
33 bool cal3(int a, int b, int c, int d, int m1, int m2, int m3)
34 {
35     double r1;
36     double r2;
37     double r3;
38     r1 = cal(b, m1, c);
39     r2 = cal(r1, m2, d);
40     r3 = cal(a, m3, r2);
41     if (r3 == 24)
42     {
43         cout << "(" << a << mark_char[m1 - 1] << "((" << b << mark_char[m2 - 1] << c << ")" << mark_char[m3 - 1] << d << "))" << endl;
44         return 1;
45     }
46     return 0;
47 }//第三种r1=b$c,r2=r1$d,r3=a$r2;
48 
49 bool cal4(int a, int b, int c, int d, int m1, int m2, int m3)
50 {
51     double r1;
52     double r2;
53     double r3;
54     r1 = cal(c, m1, d);
55     r2 = cal(b, m2, r1);
56     r3 = cal(a, m3, r2);
57     if (r3 == 24)
58     {
59         cout << "(" << a << mark_char[m1 - 1] << "(" << b << mark_char[m2 - 1] << "(" << c << mark_char[m3 - 1] << d << ")))" << endl;
60         return 1;
61     }
62     return 0;
63 }//第四种r1=c$d,r2=b$r1,r3=a$r2;
64 
65 bool cal5(int a, int b, int c, int d, int m1, int m2, int m3)
66 {
67     double r1;
68     double r2;
69     double r3;
70     r1 = cal(a, m1, b);
71     r2 = cal(c, m3, d);
72     r3 = cal(r1, m2, r2);
73     if (r3 == 24)
74     {
75         cout << "((" << a << mark_char[m1 - 1] << b << ")" << mark_char[m2 - 1] << "(" << c << mark_char[m3 - 1] << d << "))" << endl;
76         return 1;
77     }
78     return 0;
79 }//第五种r1=a$b,r2=c$d,r3=r1$r2;

接下来是12种的符号的排列情况,如果有一种括号情况满足,我们就返回true,否则返回false

 1 bool all_cal(int a, int b, int c, int d)
 2 {
 3     for (int i = 1; i <= 4; i++)
 4         for (int j = 1; j <= 4; j++)
 5             for (int k = 1; k <= 4; k++)
 6             {
 7                 if (cal1(a, b, c, d, i, j, k) == true || cal2(a, b, c, d, i, j, k) == true || cal3(a, b, c, d, i, j, k) == true || cal4(a, b, c, d, i, j, k) == true || cal5(a, b, c, d, i, j, k) == true)
 8                     return 1;
 9             }
10     return 0;
11 }

最后是在总判断函数中写入24种的abcd排列情况

 1 bool judge(int a, int b, int c, int d)
 2 {
 3     int all[24][4] = {
 4         {a,b,c,d},{a,b,d,c},{a,c,b,d},{a,c,d,b},{a,d,b,c},{a,d,c,b},
 5         {b,a,c,d},{b,a,d,c},{b,c,a,d},{b,c,d,a},{b,d,a,c},{b,d,c,a},
 6         {c,a,b,d},{c,a,d,b},{c,b,a,d},{c,b,d,a},{c,d,a,b},{c,d,b,a},
 7         {d,a,b,d},{d,a,d,b},{d,b,a,c},{d,b,c,a},{d,c,a,b},{d,c,b,a},
 8     };
 9     for (int i = 0; i < 24; i++)
10     {
11         if (all_cal(all[i][0], all[i][1], all[i][2], all[i][3]))
12             return 1;
13     }
14     return 0;
15 }

主函数调用judge就完成整个算法了✿✿ヽ(°▽°)ノ✿

1 int main()
2 {
3     int a, b, c, d;
4     cin >> a >> b >> c >> d;
5     if (!judge(a, b, c, d))
6         cout << "凑不成24点" << endl;
7 
8 }

失败的话会显示“凑不成24点”

其实这个算法的话我写的可以说基本没有优化,就是枚举所有情况实现的,csdn上有大佬是有更好的思路的,这篇文章也是看了csdn的大佬的代码然后自己修修补补写出来的(我原来看的那篇有bug,大佬自己没发现好像。。。)

就酱

睡觉!

  

原文地址:https://www.cnblogs.com/luoyoucode/p/13551552.html