7-16 用扑克牌计算24点 (6分)(附详细讲解)

本文详细介绍了一种解决24点游戏的算法,通过列举所有可能的数字排列和运算符组合,寻找使得四个数通过加减乘除运算得到24的表达式。文章解释了如何创建运算符和数字的排列,定义计算函数,并通过多种括号组合改变运算优先级,最终输出符合条件的表达式。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一副扑克牌的每张牌表示一个数(J、Q、K 分别表示 11、12、13,两个司令都表示 6)。任取4 张牌,即得到 4 个 1~13 的数,请添加运算符(规定为加+ 减- 乘* 除/ 四种)使之成为一个运算式。每个数只能参与一次运算,4 个数顺序可以任意组合,4 个运算符任意取 3 个且可以重复取。运算遵从一定优先级别,可加括号控制,最终使运算结果为 24。请输出一种解决方案的表达式,用括号表示运算优先。如果没有一种解决方案,则输出 -1 表示无解。
输入格式:
输入在一行中给出 4 个整数,每个整数取值在 [1, 13]。
输出格式:
输出任一种解决方案的表达式,用括号表示运算优先。如果没有解决方案,请输出 -1。
输入样例:
2 3 12 12
输出样例:
((3-2)*12)+12

分析

目前不存在一个高效且明确的算法能计算出24点,如果存在,人们早就使用了。但是我们知道,四张扑克牌的排列只有24种可能(4x3x2x1)运算符号的排列有64(4x4x4)种可能,如果某4张能得到24点,那么这四张牌的表达式一定在24x64x5(5代表5种两对括号排列方式)中的某一项,这样我们就得到解决方法:程序遍历每一种表达式,找到一个符合要求的表达式并输出。这种方法叫枚举(暴力破解),这是一个明确低效的算法,人脑无法使用这种算法来完成24点,但是计算机却可以很容易使用枚举(暴力破解)法来求解24点问题。

此算法分为以下几个具体步骤:
1、首先创建两个字符数组,前者存放加减乘除四个符号,后者存放64种运算符号表达式,通过移动第一个字符数组中的元素下标来创造64种符号表达式。
2、然后创建一个整型数组,该数组容纳24种四张扑克牌的排列,我们可以通过移动元素下标来完成此排列。
3、创建一个计算函数,此函数接受两个数与对应的运算符,然后返回这两个数和对应运算符求解后的值。
4、每次用64种运算符构成的表达式中的一种与24种操作数的排列做运算,如果结果等于24,就输出。注意输出格式!
5、每次输出正确表达式时都需要两对括号。因为程序永远是从左到右计算,因此要通过括号来改变计算顺序。现在讨论两对括号的排列方式:
(1)((3-2)x12)+12
(2)(3-(2x12))+12
(3)(3-2)x(12+12)
(4)3-((2x12)+12)
(5)3-(2x(12+12))

代码展示:

#include<stdio.h>

/*接受两数和对应的算术符号,然后返回两数处理后的值*/
float operation(float a,float b,char c)
{
	float sum=0;
	
	switch(c)
	{
		case '+':
			sum=a+b;
		break;

		case '-':
			sum=a-b;
		break;

		case '*':
			sum=a*b;
		break;

		case '/':
			sum=a/b;
		break;
	}
	return sum;
}
/*每次用一种符号表达式与24种排列做运算*/
int number(char* a,float*num)
{
	float t1=0;
	float t2=0;
	float sum=0;
	int i,j,k,l;
	
	for(i=0;i<4;++i)
	  for(j=0;j<4;++j)
		  for(k=0;k<4;++k)
				for(l=0;l<4;++l)
					if( i!=j && i!=k && i!=l && j!=k && j!=l && k!=l )
					{
						/*((3-2)x12)+12形式*/
						t1=operation(num[i],num[j],*a);
						t2=operation(t1,num[k],*(a+1));
						sum=operation(t2,num[l],*(a+2));
						if(sum==24)
						{
							printf("((%.0f%c%.0f)%c%.0f)%c%.0f",num[i],*a,num[j],*(a+1),num[k],*(a+2),num[l]);
							return 1;
						}
						/*(3-(2x12))+12形式*/
						t1=operation(num[j],num[k],*(a+1));
						t2=operation(num[i],t1,*a);
						sum=operation(t2,num[l],*(a+2));
						if(sum==24)
						{
							printf("(%.0f%c(%.0f%c%.0f))%c%.0f",num[i],*a,num[j],*(a+1),num[k],*(a+2),num[l]);
							return 1;
						}
						/*(3-2)x(12+12)形式*/
						t1=operation(num[i],num[j],*a);
						t2=operation(num[k],num[l],*(a+2));
						sum=operation(t1,t2,*(a+1));
						if(sum==24)
						{
							printf("(%.0f%c%.0f)%c(%.0f%c%.0f)",num[i],*a,num[j],*(a+1),num[k],*(a+2),num[l]);
							return 1;
						}
						/*3-(2*(12+12))形式*/
						t1=operation(num[k],num[l],*(a+2));
						t2=operation(num[j],t1,*(a+1));
						sum=operation(num[i],t2,*a);
						if(sum==24)
						{
							printf("%.0f%c(%.0f%c(%.0f%c%.0f))",num[i],*a,num[j],*(a+1),num[k],*(a+2),num[l]);
							return 1;
						}
						/*3-((2*12)+12)*/
						t1=operation(num[j],num[k],*(a+1));
						t2=operation(t1,num[l],*(a+2));
						sum=operation(num[i],t2,*a);
						if(sum==24)
						{
							printf("%.0f%c((%.0f%c%.0f)%c%.0f)",num[i],*a,num[j],*(a+1),num[k],*(a+2),num[l]);
							return 1;
						}
					}
	return 0;
}
int main(void)
{
	char a[6]="+-*/";
	char b[64][5]={0};
	float num[4]={0};
	int i=0,j=0,k=0,l=0,m=0;
	int count=0;

	for(i=0;i<4;++i)
	scanf("%f",&num[i]);
	
	for(i=0;i<4;++i)
		for(j=0;j<4;++j)
			for(k=0;k<4;++k)
			{	
			    /*b数组存放64种符号表达式*/
				b[l][m]=a[i];
				b[l][m+1]=a[j];
				b[l][m+2]=a[k];
				++l;
			}
	for(i=0;i<64;++i)
		if(number(b[i],num))/*等于24,输出并终止程序*/
			return 0;
	printf("-1");
	return 0;
}

此时四个数要用浮点类型变量存储,因为表达式里有除号存在!

### 关于扑克牌计算24的游戏规则 “算24”的游戏目标是利用四张扑克牌上的数字,通过加减乘除以及括号的组合运算得出结果为24。该游戏不仅能够提升玩家的逻辑思维能力和快速反应能力,还能增强对基本数学运算的理解和应用。 #### 基本规则 1. 使用一副标准扑克牌,通常选取A到K共13种牌型参与游戏。其中A代表1,J代表11,Q代表12,K代表13[^2]。 2. 随机抽取四张牌作为一组数据源,每张牌所对应的数值即为可使用的操作数。 3. 利用加法、减法、乘法、除法四种基本运算符,并可以适当加入括号改变优先级顺序来构建表达式使得最终的结果等于24。 4. 每次抽取出的四个数字均需且只能被使用一次,在整个过程中不允许重复或者遗漏任何一个给定值[^1]。 #### 解题策略与技巧 为了提高解决此类问题效率,以下是几种常见有效方法: - **解因子法**:尝试找到接近但小于24的目标中间产物比如8*3=24 或者6 * 4 = 24等形式,再考虑如何由现有卡片组成这些部积。 - **倍增调整法**:如果发现某些特定排列相乘后会超过预期,则思考能否借助其他剩余项将其拉回到合理范围内。例如当存在较大偶数时(如8),可以通过寻找其一半大小的奇配对形成新的可能性路径。 ```python def can_get_24(nums): import itertools operators = ['+', '-', '*', '/'] def evaluate(expr): try: return eval(expr) except ZeroDivisionError: return None permutations_of_numbers = list(itertools.permutations(nums)) combinations_of_operations = list(itertools.product(operators, repeat=len(nums)-1)) for numbers in permutations_of_numbers: for ops in combinations_of_operations: exprs = [] # Generate all possible parenthesized expressions. n = len(numbers) if n == 1 and abs(evaluate(str(numbers[0])) - 24) < 1e-9: return True elif n >= 2: base_expr = '{} {} {}'.format(*numbers[:2],ops[0]) if n==2: exprs.append(base_expr) else: next_num_index = 2 while(next_num_index<n): new_base_expressions = set() for e in exprs or [base_expr]: temp_e = '({})'.format(e) if '+'in e or '-'in e or '*'in e or '/'in e else str(e) combined_expression_with_next_number_and_operator ='{} {} {}'.format(temp_e , ops[next_num_index-1],str(numbers[next_num_index])) new_base_expressions.add(combined_expression_with_next_number_and_operator ) exprs=new_base_expressions.copy() next_num_index+=1 results=[evaluate(ex)for ex in exprs ] if any(abs(r - 24)<1e-9 for r in results ): return True return False ``` 上述代码定义了一个函数`can_get_24`, 它接受一个列表参数 `nums`(长度应为4), 表示当前手头拥有的那几张卡牌上面显示出来的具体数值们; 函数内部运用穷举枚举的方式遍历所有可能的情况并判断是否存在满足条件的情形.
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值