N个数计算24点

N个数计算24

问题:

    N113之间的自然数,找出所有能通过加减乘除计算(每个数有且只能用一次)得到24的组合

 

计算24点常用的算法有:① 任取两个数,计算后,将结果放回去,再从剩下的数中任取两个,如此反复直到只剩下一个数;② 先构建前缀/后缀表达式,再计算该表达式;③ 用集合保存中间结果,集合间两两进行合并计算得到新集合(或者对给定的一个集合,对其所有的子集合进行合并计算)。

本文采用第一种方法。定义六种操作符:ADDSUBMULDIVRSUBRDIV,分别对应加、减、乘、除、反减和反除(反减/除:先交换两个数,再减/除)。

显然,取两个数计算时,六种计算结果可能有重复,可以对这6个结果进行去重(实际上,只要分别对加减(ADDSUBRSUB)和乘除(MULDIVRDIV)的3个计算结果进行去重判断就可以了,效率和对6个结果去重相差不大)。

另外一种剪枝方法:保存每个数上次计算时所用的操作符(初始值为空)。所取的两个数:

若某个数的上次操作符为减(SUBRSUB),那么不进行加减(ADDSUBRSUB)计算。

若某个数的上次操作符为除(DIVRDIV),那么不进行乘除(MULDIVRDIV)计算。

比如:取的两个数为 a-b c(c的上次操作符任意),如果进行加减计算的话,

a-b+c  c+a-b重复,

c-(a-b)c+b-a重复

a-b-c  c+b RSUB a重复

也就是说,上次操作符为减的,进行加减计算时,总可以转为某个上次操作符为加的表达式,因而可以不计算。同样,上次操作符为除的,不进行乘除计算。

当然,还可以考虑记录位置进行剪枝,这样避免a+b+ca+c+b都进行计算。但要注意的是:在给定的组合无解时,越多的剪枝方法,极有可能提高搜索效率,但在给定的组合有解时,很可能反而降低搜索效率

另外,对有解时输出的表达式的处理对程序的性能影响很大。如果每次计算都保存对应的表达式,会进行大量的字符串操作,严重影响性能。实际上,每次计算只要保存取出的两个数的位置和所进行计算的操作符就够了,最终需要输出表达式时,只要模拟一下递归函数调用过程,进行相应的字符串操作。

下面是程序(gcc 4.5,优化参数-O2)在T4200/2G单核下运行的结果,计算10个数,646646个组合只用了不到13分钟。


 
N113之间的数的所有组合,计算24

N

4

5

6

7

8

9

10

时间(ms)

78

610

4157

19593

160922

173766

764328

有解组合数

1362

6104

18554

50386

125969

293930

646646

总组合

1820

6188

18564

50388

125970

293930

646646

总表达式

1124776

15656645

105278906

492587616

3760744504

4535030813

19912345238

表达式A

457549

11864184

88679768

409129896

1173803224

4535030813

19912345238

表达式B

667227

3792461

16599138

83457720

2586941280

0

0

总函数调用

1482939

20950792

141892513

669790534

5258218577

6112529945

26948662625

函数调用A

603206

15849306

119160441

551913059

1576965280

6112529945

26948662625

函数调用B

879733

5101486

22732072

117877475

3681253297

0

0

其中:表达式A/B、函数调用A/B为:给定的n个数有/无解时,所处理的表达式总数和函数调用总次数。

 

    N=8N=9,两个所用时间只相差13秒,这是由于N8时,有一个组合(81)无解,判断这个组合无解需110多秒,而计算剩下的125969个组合还不要50秒。


程序代码:

  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 以下是一个示例 C 代码,用于计算 24 点问题的答案。这里假设四个数字是由用户输入的,名为 num1、num2、num3 和 num4。 ``` #include <stdio.h> #include <stdbool.h> // 定义函数,用于尝试计算 24 点问题的答案 bool calc24(int num1, int num2, int num3, int num4) { // 在这里尝试所有可能的四则运算组合 if (num1 + num2 + num3 + num4 == 24) return true; if (num1 + num2 + num3 - num4 == 24) return true; if (num1 + num2 - num3 + num4 == 24) return true; if (num1 + num2 - num3 - num4 == 24) return true; if (num1 - num2 + num3 + num4 == 24) return true; if (num1 - num2 + num3 - num4 == 24) return true; if (num1 - num2 - num3 + num4 == 24) return true; if (num1 - num2 - num3 - num4 == 24) return true; return false; } int main() { int num1, num2, num3, num4; printf("请输入四个数字: "); scanf("%d %d %d %d", &num1, &num2, &num3, &num4); // 调用 calc24 函数,并输出结果 if (calc24(num1, num2, num3, num4)) { printf("可以计算出 24\n"); } else { printf("无法计算出 24\n"); } return 0; } ``` 希望这能帮到你。如果你有其他问题,请随时告诉我。 ### 回答2: 这是一个基于C语言的计算24点的代码示例: ```c #include <stdio.h> #include <stdbool.h> // 递归函数,判断是否能得到24 bool solve(double nums[], int count) { int i, j; if (count == 1) { if (fabs(nums[0] - 24.0) < 1e-6) { // 判断是否接近24 return true; } return false; } double newNums[4]; for (i = 0; i < count; i++) { for (j = i + 1; j < count; j++) { int m, n, newCount = 0; for (m = 0; m < count; m++) { if (m != i && m != j) { newNums[newCount++] = nums[m]; } } newNums[newCount] = nums[i] + nums[j]; if (solve(newNums, newCount + 1)) { // 递归求解 return true; } newNums[newCount] = nums[i] - nums[j]; if (solve(newNums, newCount + 1)) { return true; } newNums[newCount] = nums[j] - nums[i]; if (solve(newNums, newCount + 1)) { return true; } newNums[newCount] = nums[i] * nums[j]; if (solve(newNums, newCount + 1)) { return true; } if (nums[j] != 0) { newNums[newCount] = nums[i] / nums[j]; if (solve(newNums, newCount + 1)) { return true; } } if (nums[i] != 0) { newNums[newCount] = nums[j] / nums[i]; if (solve(newNums, newCount + 1)) { return true; } } } } return false; } int main() { double nums[4]; // 存储输入的四个数字 int i; printf("请输入四个数字:\n"); for (i = 0; i < 4; i++) { scanf("%lf", &nums[i]); } if (solve(nums, 4)) { printf("可以通过加减乘除得到24!\n"); } else { printf("无法通过加减乘除得到24!\n"); } return 0; } ``` 这段代码实现了一个递归函数solve,用于判断能否通过加减乘除得到24。其中主函数会接收四个输入数字,然后调用solve函数进行判断。solve函数采用穷举法,通过循环遍历来获取两个数字,然后在新的数组中添加这两个数字的加、减、乘、除结果,并再次调用solve函数进行判断,直到只剩下一个数字为止。最终输出结果表示是否能够通过加减乘除得到24。 ### 回答3: 下面是一个使用C语言编写的计算24点的代码: ```c #include <stdio.h> #include <stdbool.h> bool isPossible(double arr[], int n, double target) { if (n == 1) { if (arr[0] == target) { return true; } return false; } for (int i = 0; i < n; i++) { for (int j = i+1; j < n; j++) { double a = arr[i]; double b = arr[j]; double newArr[n-1]; int newIndex = 0; for (int k = 0; k < n; k++) { if (k != i && k != j) { newArr[newIndex++] = arr[k]; } } newArr[newIndex] = a + b; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (a + b)) || isPossible(newArr, n-1, target / (a + b))) { return true; } newArr[newIndex] = a - b; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (a - b)) || isPossible(newArr, n-1, target / (a - b))) { return true; } newArr[newIndex] = b - a; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (b - a)) || isPossible(newArr, n-1, target / (b - a))) { return true; } newArr[newIndex] = a * b; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (a * b)) || isPossible(newArr, n-1, target / (a * b))) { return true; } if (b != 0) { newArr[newIndex] = a / b; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (a / b)) || isPossible(newArr, n-1, target / (a / b))) { return true; } } if (a != 0) { newArr[newIndex] = b / a; if (isPossible(newArr, n-1, target) || isPossible(newArr, n-1, target - a - b) || isPossible(newArr, n-1, target + a - b) || isPossible(newArr, n-1, target - a + b) || isPossible(newArr, n-1, target * (b / a)) || isPossible(newArr, n-1, target / (b / a))) { return true; } } } } return false; } int main() { double arr[4]; printf("请输入四个数字:"); scanf("%lf %lf %lf %lf", &arr[0], &arr[1], &arr[2], &arr[3]); if (isPossible(arr, 4, 24)) { printf("可以得到24。\n"); } else { printf("无法得到24。\n"); } return 0; } ``` 代码中使用了递归的思路,通过深度优先搜索的方式遍历所有可能的情况,判断是否存在满足条件的组合。程序首先会读取用户输入的四个数字,然后判断是否存在一种运算组合能够得到24。如果存在则输出"可以得到24。",否则输出"无法得到24。"。 注意:该代码只适用于输入四个数的情况,如果输入的数字个数不固定,需要进行相应的修改。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值