一、简介

本程序的思想和算法来自于C语言教材后的实训项目,程序通过用户输入四个整数计算出能够通过加减乘除得到数字24的所有表达式,程序的设计有别于一般通过穷举实现的方式,效率得到提高。算法介绍如下:

如用户输入1,2,3,4四个数字,先将其看成四个集合即{1},{2},{3},{4},整个叫做第一集群,后通过任意两个集合加减乘除{1,2},{1,3},{1,4},{2,3},{2,4},{3,4}六个集合叫做第二集群,而第三集群由第一集群和第二集群产生,而第四集群可由第一集群和第三集群以及由第二集群自身产生,最后比较第四集群所得到的的值是否24,输出结果


二、程序流程如下:

  1. 程序调用input函数处理用户输入,并同时生成四个相应的集合
  2. 调用函数calc,通过其中的list_cross函数产生第二、三、四集群
  3. 调用函数output输出,并同时删除相同的表达式
  4. 删除所有集群所占的空间,程序结束

三、主要的数据结构以及算法

为了提高计算精度,使用分数表示每一次计算结果

分数的结构 FRACTION

typedef struct{
int num;//分子
int den;//分母
}FRACTION; //注意分数的符号放在分子上

集群链表节点 s_ item

 typedef char EXPRESS[]; //存储具体的表达式,如2*3
typedef struct s_item{
FRACTION value; //集合的值 如expr为2*3,value.num=6,value.den=1
EXPRESS expr; //表达式
int flag[]; //每一个元素代表是否使用相应的数字,如用户输入了1,2,3,4,flag{1,1,0,0},表示
//集合含有数字1和2
struct s_item* next; //指向下一节点
}ITEM,*PITEM;

主要的算法

分数的四则运算:

1.声明

int commonDivisor(int a,int b);//最大公约数
int commonMultiple(int a,int b);//最小公倍数
//公倍数和公约数用于化简和计算分数 FRACTION plus(FRACTION a,FRACTION b);//分数的加法
FRACTION sub(FRACTION a,FRACTION b);//分数的减法
FRACTION multiple(FRACTION a,FRACTION b);//分数乘法
FRACTION division(FRACTION a,FRACTION b);//分数的除法

2.定义

 //最大公约数
int commonDivisor(int a,int b){
int temp=;
while(b!=){
temp=a%b;
a=b;
b=temp;
}
return a;
} //最小公倍数
int commonMultiple(int a,int b){
return a*b/commonDivisor(a,b);
} //分数的加法
FRACTION plus(FRACTION a,FRACTION b){ if(a.den==b.den){ //分母相同 a.num=a.num+b.num;
}else{
int cm=commonMultiple(a.den,b.den);
a.num=a.num*(cm/a.den)+b.num*(cm/b.den);
a.den=cm;
} //简化a,分子分母同除公约数
int cm= commonDivisor(abs(a.num),a.den);
a.num/=cm;
a.den/=cm; return a;
} //分数减法
FRACTION sub(FRACTION a,FRACTION b){ if(a.den==b.den){ //分母相同 a.num=a.num-b.num;
}else{
int cm=commonMultiple(a.den,b.den);
a.num=a.num*(cm/a.den)-b.num*(cm/b.den);
a.den=cm;
}
//简化a,分子分母同除公约数
int cm= commonDivisor(abs(a.num),a.den);
a.num/=cm;
a.den/=cm; return a;
} //分数乘法
FRACTION multiple(FRACTION a,FRACTION b){ a.num*=b.num;
a.den*=b.den; int cm= commonDivisor(abs(a.num),a.den);
a.num/=cm;
a.den/=cm; return a;
} //分数的除法
FRACTION division(FRACTION a,FRACTION b){
int temp;
if(b.num==){
a.num=;
a.den=;
return a;//不能除0 ,返回分子,分母为0,作为标志
}else if(b.num>){
temp=b.num;
b.num=b.den;
b.den=temp;
}else{
temp =abs(b.num);
b.num=b.den;
b.den=temp;
b.num*=-;
}
return multiple(a,b);
}

集合之间的加减乘除产生新集合

1.声明

PITEM add(PITEM a,PITEM b); //两个相加
PITEM divide(PITEM a,PITEM b); //两个相除
PITEM mutiply(PITEM a,PITEM b); //两个相乘
PITEM subtract(PITEM a,PITEM b); //两个相减

2.定义

 PITEM add(PITEM a,PITEM b) //两个相加
{ PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
x->value=plus(a->value,b->value); int m;
for(m=;m<;m++){
x->flag[m]=;
} int k=;
x->expr[k]='(';
int j;
for(j=;a->expr[j]!='\0';j++){
x->expr[++k]=a->expr[j];
}
x->expr[++k]='+';
for(j=;b->expr[j]!='\0';j++){
x->expr[++k]=b->expr[j];
}
x->expr[++k]=')';
x->expr[++k]='\0'; int i=;
for(i=;i<;i++){
if(a->flag[i]==){
x->flag[i]=;
} if(b->flag[i]==){
x->flag[i]=;
} } x->next=NULL; return x;
} PITEM divide(PITEM a,PITEM b){ //集合相除
PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
x->value=division(a->value,b->value); int m;
for(m=;m<;m++){
x->flag[m]=;
}
if(x->value.num==&&x->value.den==){
free(x);
return NULL;
} int k=;
x->expr[k]='(';
int j;
for(j=;a->expr[j]!='\0';j++){
x->expr[++k]=a->expr[j];
}
x->expr[++k]='/';
for(j=;b->expr[j]!='\0';j++){
x->expr[++k]=b->expr[j];
}
x->expr[++k]=')';
x->expr[++k]='\0'; int i=;
for(i=;i<;i++){
if(a->flag[i]==){
x->flag[i]=;
} if(b->flag[i]==){
x->flag[i]=;
} } x->next=NULL;
return x;
}
PITEM mutiply(PITEM a,PITEM b)//两个相乘
{
PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
x->value=multiple(a->value,b->value);
int m;
for(m=;m<;m++){
x->flag[m]=;
}
int k=;
x->expr[k]='(';
int j;
for(j=;a->expr[j]!='\0';j++){
x->expr[++k]=a->expr[j];
}
x->expr[++k]='*';
for(j=;b->expr[j]!='\0';j++){
x->expr[++k]=b->expr[j];
}
x->expr[++k]=')';
x->expr[++k]='\0'; int i=;
for(i=;i<;i++){
if(a->flag[i]==){
x->flag[i]=;
} if(b->flag[i]==){
x->flag[i]=;
} } x->next=NULL;
return x;
} PITEM subtract(PITEM a,PITEM b){ //相减
PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
x->value=sub(a->value,b->value);
int m;
for(m=;m<;m++){
x->flag[m]=;
}
int k=;
x->expr[k]='(';
int j;
for(j=;a->expr[j]!='\0';j++){
x->expr[++k]=a->expr[j];
}
x->expr[++k]='-';
for(j=;b->expr[j]!='\0';j++){
x->expr[++k]=b->expr[j];
}
x->expr[++k]=')';
x->expr[++k]='\0'; int i=;
for(i=;i<;i++){
if(a->flag[i]==){
x->flag[i]=;
} if(b->flag[i]==){
x->flag[i]=;
} } x->next=NULL;
return x;
}

核心代码

产生新集群 list_cross

 //比较集群之间是否有相同数字
int cmp(PITEM left,PITEM right){
int i;
for(i=;i<;i++){
if(left->flag[i]==&&right->flag[i]==){
return ;
}
}
return ;
} //结合两个集群产生下一个集群
void list_cross(PITEM left,PITEM right,PITEM result){ PITEM p,q;
for(p=left->next;p!=NULL;p=p->next){ //循环调用两个集群中所有集合
for(q=right->next;q!=NULL;q=q->next)
if(cmp(p,q)==){ //只有两集合不含相同数字才运算
PITEM temp=NULL;
if((temp=add(p,q))!=NULL){
temp->next=result->next;
result->next=temp;
}
if((temp=subtract(p,q))!=NULL){
temp->next=result->next;
result->next=temp;
}
if((temp=divide(p,q))!=NULL){
temp->next=result->next;
result->next=temp;
}
if((temp=mutiply(p,q))!=NULL){
temp->next=result->next;
result->next=temp;
} }
}
}

因为用户有可能输入相同的数字,所以要消除相同的表达式:

消除重复表达式

 PITEM p=p4_head->next;  //p指向第四集群的头结点,第四集群即最后四个数字都已经使用的集合 

      //消除重复的表达式 

      PITEM q,pre;
for(;p!=NULL;p=p->next){
for(q=p->next,pre=p;q!=NULL;){
if(strcmp(p->expr,q->expr)==){ pre->next=q->next;
PITEM temp=q; //pre为p的前一个节点
q=q->next; free(temp);//消失重复点;
temp=NULL; }else{
q=q->next;
pre=pre->next;
}
}
}

判断集合的值,输出结果

     //输出
p=p4_head->next;
while(p!=NULL){
if(p->value.num==&&p->value.den==){ puts(p->expr); } p=p->next;
}

四、运行

               

源代码地址:C语言实现24点src

C语言实现24点程序的更多相关文章

  1. C语言学习书籍推荐《学通C语言的24堂课》下载

    下载地址:点我 编辑推荐 <学通C语言的24堂课>:用持续激励培养良好习惯以良好习惯铸就伟大梦想——致亲爱的读者朋友在开始学习<学通C语言的24堂课>的同时,强烈建议读者朋友同 ...

  2. C语言之简易了解程序环境

    C语言之简易了解程序环境 大纲: 程序的翻译环境 预编译 编译 汇编 链接 程序的运行环境 在ANSI C的任何一种实现中,存在两个不同的环境. 第1种是翻译环境,在这个环境中源代码被转换为可执行的机 ...

  3. 基于php基础语言编写的小程序之计算器

    基于php基础语言编写的小程序之计算器 需求:在输入框中输入数字进行加.减.乘.除运算(html+php) 思路: 1首先要创建输入数字和运算符的输入框,数字用input的text属性,运算符用sel ...

  4. 利用Scala语言开发Spark应用程序

    Spark内核是由Scala语言开发的,因此使用Scala语言开发Spark应用程序是自然而然的事情.如果你对Scala语言还不太熟悉,可 以阅读网络教程A Scala Tutorial for Ja ...

  5. SAS进阶《深入解析SAS》之开发多语言支持的SAS程序

    SAS进阶<深入解析SAS>之开发多语言支持的SAS程序 1. 多语言支持的应用程序是指该程序在世界给第使用时,其能够处理的数据,以及处理数据的方式.信息展现的方式都符合当地的语言.文化习 ...

  6. JAVA 基础编程练习题24 【程序 24 根据输入求输出】

    24 [程序 24 根据输入求输出] 题目:给一个不多于 5 位的正整数,要求:一.求它是几位数,二.逆序打印出各位数字. package cskaoyan; public class cskaoya ...

  7. [转载] 使用C/C++语言编写基于DSP程序的注意事项

    原文地址:『转』使用C/C++语言编写基于DSP程序的注意事项作者:skysmile   1.不影响执行速度的情况下,可以使用c或c/c++语言提供的函数库,也可以自己设计函数,这样更易于使用“裁缝师 ...

  8. 程序员之---C语言细节24(段错误、类型提升、sizeof &#39;A&#39;)

    主要内容:段错误.类型提升.sizeof  'A' #include <stdio.h> int main() { union test{ char a[10]; int b; }u; i ...

  9. 平方根的C语言实现(三) ——最终程序实现

    版权申明:本文为博主窗户(Colin Cai)原创,欢迎转帖.如要转贴,必须注明原文网址 http://www.cnblogs.com/Colin-Cai/p/7223254.html 作者:窗户 Q ...

随机推荐

  1. windows下使用RedisCluster集群简单实例

    一.开发环境 ruby环境准备 下载 64位的 RubyInstaller并安装 地址http://rubyinstaller.org/downloads/勾选下面三个不用配置环境变量 Image.p ...

  2. ALGO-7_蓝桥杯_算法训练_逆序对

    出处:http://blog.csdn.net/enjoying_science/article/details/44114035 (有难度,以后回来填坑) 阅读代码中: #include<st ...

  3. php提交表单校验例子

    <!DOCTYPE HTML> <meta http-equiv="Content-Type" content="text/html; charset= ...

  4. sql编程中流程控制 IF ……THEN……ELSEIF……THEN………END IF

    写mysql存储过程应注意的几点: 1.声明变量(declare)时要注意字符集,用变量存储表字段时,表字段与变量的字符编码要一致. 2.mysql的字符合并不能用‘+’号,必须用concat函数. ...

  5. JAVA的非对称加密算法RSA——加密和解密

    原文转载至:https://www.cnblogs.com/OnlyCT/p/6586856.html 第一部分:RSA算法原理与加密解密 一.RSA加密过程简述 A和B进行加密通信时,B首先要生成一 ...

  6. Windows7下搭建Eclipse+Python开发环境

    机器: Windows7_x86_64 前提: 机器已成功安装Python2.7,并配置好环境变量. 步骤: 一.Eclipse的安装 Eclipse是基于java的一个应用程序,因此需要一个java ...

  7. RmNet,CDC-ECM ,NDIS,RNDIS区别

    RmNet和CDC-ECM区别:更像是两种拨号方式的区别,RmNet获取公网IP,ECD-ECM获取局域网IP. 在高通平台上,rmnet driver 和标准的CDC-ECM是有区别的,rmnet ...

  8. 【Codeforces】CF 467 C George and Job(dp)

    题目 传送门:QWQ 分析 dp基础题. $ dp[i][j] $表示前i个数分成j组的最大和. 转移显然. 吐槽:做cf题全靠洛谷翻译苟活. 代码 #include <bits/stdc++. ...

  9. java管道通信

    介绍:不同的数据源之间通过建立管道进行数据通信.如图: 线程之间通信最好的方式就是采用管道机制,类似水管一样,水管可以对接,组合成各种具有过滤性质的管道,管道和线程灵活使用,可以提高效率.(Chann ...

  10. 「CQOI2016」K 远点对

    /* 考虑暴力 可以n ^ 2枚举点对 然后用一个容量为2k的小根堆来维护第k大 kd-tree呢就是来将这个暴力优化, 每次先找远的并且最远距离不如堆顶的话就不继续找下去 貌似挺难构造数据卡的 */ ...