C语言实现24点程序

 

       一、简介

              本程序的思想和算法来自于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

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

 1 //最大公约数 
 2 int commonDivisor(int a,int b){
 3     int temp=0;
 4     while(b!=0){
 5         temp=a%b;
 6         a=b;
 7         b=temp;
 8     }
 9     return a;
10 }
11 
12 //最小公倍数 
13 int commonMultiple(int a,int b){
14     return a*b/commonDivisor(a,b);
15 }
16 
17 
18 //分数的加法 
19 FRACTION plus(FRACTION a,FRACTION b){
20     
21     if(a.den==b.den){ //分母相同 
22         
23         a.num=a.num+b.num;
24     }else{
25         int cm=commonMultiple(a.den,b.den);
26         a.num=a.num*(cm/a.den)+b.num*(cm/b.den);
27         a.den=cm;
28     }
29     
30     //简化a,分子分母同除公约数 
31     int cm= commonDivisor(abs(a.num),a.den); 
32     a.num/=cm;
33     a.den/=cm;
34     
35     return a;
36 }
37 
38 //分数减法 
39 FRACTION sub(FRACTION a,FRACTION b){
40     
41     if(a.den==b.den){ //分母相同 
42         
43         a.num=a.num-b.num;
44     }else{
45         int cm=commonMultiple(a.den,b.den);
46         a.num=a.num*(cm/a.den)-b.num*(cm/b.den);
47         a.den=cm;
48     }
49     //简化a,分子分母同除公约数 
50     int cm= commonDivisor(abs(a.num),a.den); 
51     a.num/=cm;
52     a.den/=cm;
53     
54     return a;
55 }
56 
57 //分数乘法 
58 FRACTION multiple(FRACTION a,FRACTION b){
59      
60      a.num*=b.num;
61      a.den*=b.den;
62      
63     int cm= commonDivisor(abs(a.num),a.den); 
64     a.num/=cm;
65     a.den/=cm;
66     
67     return a;
68 }
69 
70 
71 //分数的除法 
72 FRACTION division(FRACTION a,FRACTION b){
73     int temp;
74   if(b.num==0){
75        a.num=0;
76        a.den=0;
77        return a;//不能除0 ,返回分子,分母为0,作为标志 
78   }else if(b.num>0){
79          temp=b.num;
80          b.num=b.den;
81          b.den=temp;
82   }else{
83         temp =abs(b.num);
84          b.num=b.den;
85          b.den=temp;
86          b.num*=-1;
87   }
88   return multiple(a,b);
89 }

 

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

       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.定义

  1 PITEM add(PITEM a,PITEM b) //两个相加 
  2 {    
  3     
  4       PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
  5       x->value=plus(a->value,b->value);
  6       
  7       int m;
  8       for(m=0;m<4;m++){
  9            x->flag[m]=0;
 10       }
 11       
 12 
 13       int k=0;
 14       x->expr[k]='(';
 15       int j;
 16       for(j=0;a->expr[j]!='\0';j++){
 17             x->expr[++k]=a->expr[j];
 18       }
 19       x->expr[++k]='+'; 
 20       for(j=0;b->expr[j]!='\0';j++){
 21             x->expr[++k]=b->expr[j];
 22       }
 23       x->expr[++k]=')';
 24       x->expr[++k]='\0';
 25         
 26     
 27       int i=0;
 28       for(i=0;i<4;i++){
 29              if(a->flag[i]==1){
 30                      x->flag[i]=1;
 31              }
 32             
 33             if(b->flag[i]==1){
 34                 x->flag[i]=1;
 35             }
 36              
 37              
 38       }
 39       
 40       x->next=NULL; 
 41      
 42       return x;
 43 }
 44 
 45 
 46 PITEM divide(PITEM a,PITEM b){ //集合相除 
 47      PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
 48       x->value=division(a->value,b->value);
 49       
 50            int m;
 51       for(m=0;m<4;m++){
 52            x->flag[m]=0;
 53       }
 54       if(x->value.num==0&&x->value.den==0){
 55              free(x);
 56              return NULL;
 57       }
 58       
 59          int k=0;
 60       x->expr[k]='(';
 61       int j;
 62       for(j=0;a->expr[j]!='\0';j++){
 63             x->expr[++k]=a->expr[j];
 64       }
 65       x->expr[++k]='/'; 
 66       for(j=0;b->expr[j]!='\0';j++){
 67             x->expr[++k]=b->expr[j];
 68       }
 69       x->expr[++k]=')';
 70       x->expr[++k]='\0';
 71       
 72       int i=0;
 73       for(i=0;i<4;i++){
 74              if(a->flag[i]==1){
 75                      x->flag[i]=1;
 76              }
 77             
 78             if(b->flag[i]==1){
 79                 x->flag[i]=1;
 80             }
 81              
 82              
 83       }
 84       
 85       x->next=NULL; 
 86       return x;
 87 }
 88 PITEM mutiply(PITEM a,PITEM b)//两个相乘 
 89 {
 90       PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
 91       x->value=multiple(a->value,b->value);
 92            int m;
 93       for(m=0;m<4;m++){
 94            x->flag[m]=0;
 95       }
 96          int k=0;
 97       x->expr[k]='(';
 98       int j;
 99       for(j=0;a->expr[j]!='\0';j++){
100             x->expr[++k]=a->expr[j];
101       }
102       x->expr[++k]='*'; 
103       for(j=0;b->expr[j]!='\0';j++){
104             x->expr[++k]=b->expr[j];
105       }
106       x->expr[++k]=')';
107       x->expr[++k]='\0';
108       
109       int i=0;
110       for(i=0;i<4;i++){
111              if(a->flag[i]==1){
112                      x->flag[i]=1;
113              }
114             
115             if(b->flag[i]==1){
116                 x->flag[i]=1;
117             }
118              
119              
120       }
121       
122       x->next=NULL; 
123       return x;
124 }
125 
126 
127 PITEM subtract(PITEM a,PITEM b){  //相减 
128      PITEM x=(struct s_item*)malloc(sizeof(struct s_item));
129       x->value=sub(a->value,b->value);
130            int m;
131       for(m=0;m<4;m++){
132            x->flag[m]=0;
133       }
134          int k=0;
135       x->expr[k]='(';
136       int j;
137       for(j=0;a->expr[j]!='\0';j++){
138             x->expr[++k]=a->expr[j];
139       }
140       x->expr[++k]='-'; 
141       for(j=0;b->expr[j]!='\0';j++){
142             x->expr[++k]=b->expr[j];
143       }
144       x->expr[++k]=')';
145       x->expr[++k]='\0';
146       
147       int i=0;
148       for(i=0;i<4;i++){
149              if(a->flag[i]==1){
150                      x->flag[i]=1;
151              }
152             
153             if(b->flag[i]==1){
154                 x->flag[i]=1;
155             }
156              
157              
158       }
159       
160       x->next=NULL; 
161       return x;
162 }
View Code  

 

        核心代码

          产生新集群 list_cross

 1 //比较集群之间是否有相同数字 
 2 int cmp(PITEM left,PITEM right){
 3     int i;
 4     for(i=0;i<4;i++){
 5         if(left->flag[i]==1&&right->flag[i]==1){
 6             return 1;
 7         }
 8     }
 9     return 0;
10 }
11 
12 //结合两个集群产生下一个集群 
13 void list_cross(PITEM left,PITEM right,PITEM result){
14     
15         PITEM p,q;
16         for(p=left->next;p!=NULL;p=p->next){       //循环调用两个集群中所有集合 
17         for(q=right->next;q!=NULL;q=q->next)
18              if(cmp(p,q)==0){         //只有两集合不含相同数字才运算 
19                    PITEM temp=NULL;
20                    if((temp=add(p,q))!=NULL){
21                          temp->next=result->next;
22                          result->next=temp;
23                    } 
24                     if((temp=subtract(p,q))!=NULL){
25                          temp->next=result->next;
26                          result->next=temp;
27                    } 
28                     if((temp=divide(p,q))!=NULL){
29                          temp->next=result->next;
30                          result->next=temp;
31                    } 
32                     if((temp=mutiply(p,q))!=NULL){
33                          temp->next=result->next;
34                          result->next=temp;
35                    } 
36                   
37              }
38     }
39 }

           

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

         消除重复表达式

 1 PITEM p=p4_head->next;  //p指向第四集群的头结点,第四集群即最后四个数字都已经使用的集合 
 2 
 3      //消除重复的表达式 
 4      
 5      PITEM q,pre;
 6      for(;p!=NULL;p=p->next){
 7          for(q=p->next,pre=p;q!=NULL;){
 8                 if(strcmp(p->expr,q->expr)==0){
 9                          
10                          pre->next=q->next;
11                          PITEM temp=q;       //pre为p的前一个节点 
12                          q=q->next;
13                         
14                          free(temp);//消失重复点; 
15                          temp=NULL;
16                          
17                 }else{
18                     q=q->next;
19                     pre=pre->next;
20                 }
21          }
22      }

     

       判断集合的值,输出结果

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


         p=p->next;
         } 

     

四、运行

                    

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

 

posted @ 2018-01-12 20:06  鱼儿游上天  阅读(8279)  评论(0编辑  收藏  举报