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

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM