对给定四个1~10的正整数求解计算24点的运算过程
效果截图
源码
/* 头文件引入 */
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
/* 问题分析 */
/*
假设四个数排列顺序为 a,b,c,d
则其计算顺序总共有:
1.((a?b)?c)?d
2.(a?b)?(c?d)
3.(a?(b?c)?)d
4.a?((b?c)?d)
5.a?(b?(c?d))
其中?代表(+ - * /)中的任意一个运算符号
排列有24种可能,计算顺序有5种可能,运算符号有64种可能,暴力破解有7680种可能,远远小于计算机一秒能执行指令的条数
设计算法时,先遍历所有的四数排列顺序,再遍历计算顺序,最后再遍历运算符号,由于问题规模不大,可以通过暴力破解得到运算结果。
*/
/* 常量定义 */
#define LENGTHARRAY 300 //数组长度
#define LENGTHANSWER 20 //答案长度
#define MIN 1e-6 //绝对值最接近0的代表数
/* 数据结构定义 */
typedef struct answer //答案结构
{
char s[LENGTHARRAY][LENGTHANSWER]; //答案数组
int length; //答案数组长度
}Answer;
/* 全局变量定义 */
float number[4]; //四个1~10的正整数
float nums[24][4]; //排列好的四个正整数列表
char operater[4]={'+','-','*','/'}; //加减乘除
Answer a; //答案数组
/* 函数定义 */
void input(); //输入四个正整数
void arrange(); //对输入的四个正整数进行排列
float count(float n1,float n2,char op); //对两数和运算符计算
void maybe_01(float n[]); //第一种可能的运算顺序(1.((a?b)?c)?d )
void maybe_02(float n[]); //第二种可能的运算顺序(2.(a?b)?(c?d) )
void maybe_03(float n[]); //第三种可能的运算顺序(3.(a?(b?c)?)d )
void maybe_04(float n[]); //第四种可能的运算顺序(4.a?((b?c)?d) )
void maybe_05(float n[]); //第五种可能的运算顺序(5.a?(b?(c?d)) )
void getAnswer(); //破解答案
void print(); //输出所有答案
/* 主函数 */
int main()
{
input();
arrange();
getAnswer();
print();
system("pause"); //按任意键继续
return 0;
}
/* 函数实现 */
void input() //输入四个正整数
{
printf("\n请分别输入四个1~10的正整数(以空格隔开):\n");
scanf("%f %f %f %f",&number[0],&number[1],&number[2],&number[3]);
printf("输入完毕!\n");
}
void arrange() //对输入的四个正整数进行排列(abcd,abdc,acbd,acdb...总24中可能)
{
printf("\n正在对四个正整数进行排列!\n");
int v,w,x,y;
int i=0;
for(v=0;v<4;v++)
{
for(w=0;w<4;w++)
{
for(x=0;x<4;x++)
{
for(y=0;y<4;y++)
{
if(!(v==w||v==x||v==y||w==x||w==y||x==y))
{
nums[i][0]=number[v];
nums[i][1]=number[w];
nums[i][2]=number[x];
nums[i][3]=number[y];
i++;
}
}
}
}
}
printf("排列完毕!\n");
}
float count(float n1,float n2,char op) //对两数和运算符计算
{
switch(op)
{
case '+':
return n1+n2;
break;
case '-':
return n1-n2;
break;
case '*':
return n1*n2;
break;
case '/':
if(fabs(n2-0)<MIN)
{
return 1000;
}
else
{
return n1/n2;
}
break;
}
}
void maybe_01(float n[]) //第一种可能的运算顺序(1.((a?b)?c)?d )
{
int i,j,k;
char r[20]="\0";
float one,two,three;
int m,flag,p;
for(i=0;i<4;i++)
{
one=count(n[0],n[1],operater[i]);
if(fabs(one-1000)<MIN)
{
continue;
}
for(j=0;j<4;j++)
{
two=count(one,n[2],operater[j]);
if(fabs(two-1000)<MIN)
{
continue;
}
for(k=0;k<4;k++)
{
three=count(two,n[3],operater[k]);
if(fabs(three-24)<MIN)
{
r[0]='(';
r[1]='(';
r[2]=(int)n[0]+'0';
r[3]=operater[i];
r[4]=(int)n[1]+'0';
r[5]=')';
r[6]=operater[j];
r[7]=(int)n[2]+'0';
r[8]=')';
r[9]=operater[k];
r[10]=(int)n[3]+'0';
r[11]='\0';
flag=0;
for(m=0;m<a.length;m++)
{
if(strcmp(a.s[m],r)==0)
{
flag=1;
break;
}
}
if(flag==0)
{
m=a.length;
for(p=0;p<20;p++)
{
a.s[m][p]=r[p];
if(r[p]=='\0')
{
break;
}
}
a.length++;
}
}
}
}
}
}
void maybe_02(float n[]) //第二种可能的运算顺序(2.(a?b)?(c?d) )
{
int i,j,k;
char r[20]="\0";
float one,two,three;
int m,flag,p;
for(i=0;i<4;i++)
{
one=count(n[0],n[1],operater[i]);
if(fabs(one-1000)<MIN)
{
continue;
}
for(j=0;j<4;j++)
{
two=count(n[2],n[3],operater[j]);
if(fabs(two-1000)<MIN)
{
continue;
}
for(k=0;k<4;k++)
{
three=count(one,two,operater[k]);
if(fabs(three-24)<MIN)
{
r[0]='(';
r[1]=(int)n[0]+'0';
r[2]=operater[i];
r[3]=(int)n[1]+'0';
r[4]=')';
r[5]=operater[k];
r[6]='(';
r[7]=(int)n[2]+'0';
r[8]=operater[j];
r[9]=(int)n[3]+'0';
r[10]=')';
r[11]='\0';
flag=0;
for(m=0;m<a.length;m++)
{
if(strcmp(a.s[m],r)==0)
{
flag=1;
break;
}
}
if(flag==0)
{
m=a.length;
for(p=0;p<20;p++)
{
a.s[m][p]=r[p];
if(r[p]=='\0')
{
break;
}
}
a.length++;
}
}
}
}
}
}
void maybe_03(float n[]) //第三种可能的运算顺序(3.(a?(b?c)?)d )
{
int i,j,k;
char r[20]="\0";
float one,two,three;
int m,flag,p;
for(i=0;i<4;i++)
{
one=count(n[1],n[2],operater[i]);
if(fabs(one-1000)<MIN)
{
continue;
}
for(j=0;j<4;j++)
{
two=count(n[0],one,operater[j]);
if(fabs(two-1000)<MIN)
{
continue;
}
for(k=0;k<4;k++)
{
three=count(two,n[3],operater[k]);
if(fabs(three-24)<MIN)
{
r[0]='(';
r[1]=(int)n[0]+'0';
r[2]=operater[j];
r[3]='(';
r[4]=(int)n[1]+'0';
r[5]=operater[i];
r[6]=(int)n[2]+'0';
r[7]=')';
r[8]=')';
r[9]=operater[k];
r[10]=(int)n[3]+'0';
r[11]='\0';
flag=0;
for(m=0;m<a.length;m++)
{
if(strcmp(a.s[m],r)==0)
{
flag=1;
break;
}
}
if(flag==0)
{
m=a.length;
for(p=0;p<20;p++)
{
a.s[m][p]=r[p];
if(r[p]=='\0')
{
break;
}
}
a.length++;
}
}
}
}
}
}
void maybe_04(float n[]) //第四种可能的运算顺序(4.a?((b?c)?d) )
{
int i,j,k;
char r[20]="\0";
float one,two,three;
int m,flag,p;
for(i=0;i<4;i++)
{
one=count(n[1],n[2],operater[i]);
if(fabs(one-1000)<MIN)
{
continue;
}
for(j=0;j<4;j++)
{
two=count(one,n[3],operater[j]);
if(fabs(two-1000)<MIN)
{
continue;
}
for(k=0;k<4;k++)
{
three=count(n[0],two,operater[k]);
if(fabs(three-24)<MIN)
{
r[0]=(int)n[0]+'0';
r[1]=operater[k];
r[2]='(';
r[3]='(';
r[4]=(int)n[1]+'0';
r[5]=operater[i];
r[6]=(int)n[2]+'0';
r[7]=')';
r[8]=operater[j];
r[9]=(int)n[3]+'0';
r[10]=')';
r[11]='\0';
flag=0;
for(m=0;m<a.length;m++)
{
if(strcmp(a.s[m],r)==0)
{
flag=1;
break;
}
}
if(flag==0)
{
m=a.length;
for(p=0;p<20;p++)
{
a.s[m][p]=r[p];
if(r[p]=='\0')
{
break;
}
}
a.length++;
}
}
}
}
}
}
void maybe_05(float n[]) //第五种可能的运算顺序(5.a?(b?(c?d)) )
{
int i,j,k;
char r[20]="\0";
float one,two,three;
int m,flag,p;
for(i=0;i<4;i++)
{
one=count(n[2],n[3],operater[i]);
if(fabs(one-1000)<MIN)
{
continue;
}
for(j=0;j<4;j++)
{
two=count(n[1],one,operater[j]);
if(fabs(two-1000)<MIN)
{
continue;
}
for(k=0;k<4;k++)
{
three=count(n[0],two,operater[k]);
if(fabs(three-24)<MIN)
{
r[0]=(int)n[0]+'0';
r[1]=operater[k];
r[2]='(';
r[3]=(int)n[1]+'0';
r[4]=operater[j];
r[5]='(';
r[6]=(int)n[2]+'0';
r[7]=operater[i];
r[8]=(int)n[3]+'0';
r[9]=')';
r[10]=')';
r[11]='\0';
flag=0;
for(m=0;m<a.length;m++)
{
if(strcmp(a.s[m],r)==0)
{
flag=1;
break;
}
}
if(flag==0)
{
m=a.length;
for(p=0;p<20;p++)
{
a.s[m][p]=r[p];
if(r[p]=='\0')
{
break;
}
}
a.length++;
}
}
}
}
}
}
void getAnswer() //破解答案
{
int i;
printf("\n正在破解答案\n");
for(i=0;i<24;i++)
{
maybe_01(nums[i]);
maybe_02(nums[i]);
maybe_03(nums[i]);
maybe_04(nums[i]);
maybe_05(nums[i]);
}
printf("破解完毕!\n");
}
void print() //输出所有答案
{
int i,j;
if(a.length==0)
{
printf("\n无解!\n");
return;
}
printf("\n答案如下:\n");
for(i=0;i<a.length;i++)
{
printf("%d-->>",i+1);
for(j=0;j<20;j++)
{
if(a.s[i][j]=='\0')
{
printf("\n");
break;
}
else if(a.s[i][j]==':')
{
printf("10");
}
else
{
printf("%c",a.s[i][j]);
}
}
}
printf("答案打印完毕!\n\n");
}
设计思路
求解思路及理论基础:四个数abcd,排列有24种可能[ abcd , abdc , acbd , acdb , adbc , adcb …),运算顺序有5种可能[ (a?(b?c))?d , a?((b?c)?d) , ((a?b)?c)?d , (a?b)?(c?d) , a?(b?(c?d)) ],其中问号属于运算符[ + , - , * , / ]中的一种,运算符的排列有64种可能[ + + + , + + - , + + * , + + / , … ]。不去重情况下总共7680种可能,计算机每秒大概执行1亿条指令,所以说本问题可以考虑用暴力破解强行遍历所有可能进行求解。
子问题分离划分模块
1.输入并排列输入的四个数。
2.给定顺序的四个数按每个可能的运算顺序和运算符号匹配时可以算出24点且没有重复时保存到答案数组中去。
3.求解结束,输入结果。
我的设计过程
1.定义全局变量:浮点型数组number[4]用于接收用户输入的四个待求解正整数,这里肯定有小伙伴疑惑用浮点数而不是用整形int来声明,我简单说明一下(在计算的过程中有的时候会用到小数,比如以上运行截图中的,由于C语言中小数是不能判断等于与否的,只能将两数相减,再求结果的绝对值和一个极其近似于0的小数比较,小于那个数就视为原来的两数相等);浮点型数组nums[24][4]用于保存排列好的整数顺序;运算符字符数组operater[4]={’+’,’-’,’*’,’/’}用于描述运算符号;求解结果答案变量a(答案结构为
/* 常量定义 */
#define LENGTHARRAY 300 //数组长度
#define LENGTHANSWER 20 //答案长度
#define MIN 1e-6 //绝对值接近0的代表数,相当于0.0000001
/* 数据结构定义 */
typedef struct answer //答案结构
{
char s[LENGTHARRAY][LENGTHANSWER]; //答案数组
int length; //答案数组长度
}Answer;
)。
2.明确程序流程(主函数结构):数据输入->数据排列->每种可能试探->可以计算出24点且未重复则添加进答案中->试探完毕,将结果输出。
3.分别实现流程中的函数:数据输入(略);数据排列,分别设计四个整形变量v,w,x,y用来表示输入数组number的下标,将它们分别从0到3进行嵌套遍历,当它们两两不等的时候,说明这是一个符合要求的排列,即此时的一个排列abcd为number[v],number[w],number[x],number[y],此时将其加入到排好的数据列表nums中去;第一种运算顺序试探,将三个整形变量分别进行0到3嵌套遍历,在其运算符号和运算顺序下是否可以计算出24点(注意要用运算结果减去24的差的绝对值和接近于0的值相比较:小于时视为结果符号要求,而不是直接将运算结果和24比较),将结果为24点的运算式子与已经存在的答案列表中的各个式子相比较,没有重复的话就添加进答案列表中;打印答案(略)。
4.程序测试(略)