昨天我的小伙伴可能太無聊了,然后給我一道題:輸入1~8,每個數字不重復,問正確結果是什么?
這道題不難,把縱橫計算式寫出來(一共6個),1~8全排列擺放在上面的8個空位上,有幾個解就是幾種答案,沒有解說明此題有誤。
我們可以構建這個函數為:
1 int func(int a[]) 2 { 3 int b=0;//是否有誤 4 if(!b && a[2]%a[5] != 0)b=1; 5 6 if(!b && a[0]+a[1]-9 != 4)b=1; 7 if(!b && a[2]-a[3]*a[4] != 4)b=1; 8 if(!b && a[5]+a[6]-a[7] != 4)b=1; 9 if(!b && a[0]+a[2]/a[5] != 4)b=1; 10 if(!b && a[1]-a[3]*a[6] != 4)b=1; 11 if(!b && 9-a[4]-a[7] != 4)b=1; 12 return b; 13 }
如果a[] 數組中的數不能滿足如圖所示的運算公式,將返回1,能滿足將返回0
下面就是如何獲取1~8的全排序了,這個方法有很多,以下方法是書中常見的全排序方法。
1 void swap(int *a, int *b) 2 { 3 int m; 4 m = *a; 5 *a = *b; 6 *b = m; 7 } 8 void perm(int list[], int k, int m) 9 { 10 int i; 11 if(k > m) 12 { 13 for(i = 0; i <= m; i++) 14 printf("%d ", list[i]); 15 printf("\n"); 16 } 17 else 18 { 19 for(i = k; i <= m; i++) 20 { 21 swap(&list[k], &list[i]); 22 perm(list, k + 1, m); 23 swap(&list[k], &list[i]); 24 } 25 } 26 } 27 28 int main() 29 { 30 int list[] = {1, 2, 3, 4, 5, 6, 7, 8}; 31 perm(list, 0, 7); 32 return 0; 33 }
當然個人感覺最經典的還是Erlang語言的排序算法最精妙,只有這么一點:
1 -module(lib_misc). 2 -export([perms/1]). 3 perms([]) -> [[]]; 4 perms(L) -> [ [H|T] || H <- L , T <- perms( L--[H] ) ].
全排序算法和判斷表達式都有了,那么就把它們結合起來吧。只需要修改void perm(int list[], int k, int m)函數中的一部分代碼,即可打到我們要求。
1 void perm(int list[], int k, int m) 2 { 3 int i; 4 if(k > m) 5 { 6 if (!func(list)) 7 { 8 for(i = 0; i <= m; i++) 9 printf("%d ", list[i]); 10 printf("\n"); 11 } 12 } 13 else 14 { 15 for(i = k; i <= m; i++) 16 { 17 swap(&list[k], &list[i]); 18 perm(list, k + 1, m); 19 swap(&list[k], &list[i]); 20 } 21 } 22 }
8、9、10三行外面包裹了一個if判斷,就達到我們所要的目的了。
完整代碼如下:

1 #include<stdio.h> 2 int func(int a[]) 3 { 4 int b=0;//是否有誤 5 if(!b&&a[2]%a[5]!=0)b=1; 6 7 if(!b&&a[0]+a[1]-9!=4)b=1; 8 if(!b&&a[2]-a[3]*a[4]!=4)b=1; 9 if(!b&&a[5]+a[6]-a[7]!=4)b=1; 10 if(!b&&a[0]+a[2]/a[5]!=4)b=1; 11 if(!b&&a[1]-a[3]*a[6]!=4)b=1; 12 if(!b&&9-a[4]-a[7]!=4)b=1; 13 return b; 14 } 15 16 int func2(int a[]) 17 { 18 int b=0;//是否有誤 19 if(!b&&(a[0]+a[2])%a[5]!=0)b=1; 20 21 if(!b&&a[0]+a[1]-9!=4)b=1; 22 if(!b&&(a[2]-a[3])*a[4]!=4)b=1; 23 if(!b&&a[5]+a[6]-a[7]!=4)b=1; 24 if(!b&&(a[0]+a[2])/a[5]!=4)b=1; 25 if(!b&&(a[1]-a[3])*a[6]!=4)b=1; 26 if(!b&&9-a[4]-a[7]!=4)b=1; 27 return b; 28 } 29 30 void swap(int *a, int *b) 31 { 32 int m; 33 m = *a; 34 *a = *b; 35 *b = m; 36 } 37 void perm(int list[], int k, int m) 38 { 39 int i; 40 if(k > m) 41 { 42 if (!func2(list)) 43 { 44 for(i = 0; i <= m; i++) 45 printf("%d ", list[i]); 46 printf("\n"); 47 } 48 } 49 else 50 { 51 for(i = k; i <= m; i++) 52 { 53 swap(&list[k], &list[i]); 54 perm(list, k + 1, m); 55 swap(&list[k], &list[i]); 56 } 57 } 58 } 59 60 int main() 61 { 62 int list[] = {1, 2, 3, 4, 5, 6, 7, 8}; 63 perm(list, 0, 7); 64 return 0; 65 }
運行后,發現沒有給出任何一組結果,我問了一下小伙伴題是不是出錯了啊,小伙伴說木有。然后就想到是不是和運算符的優先級有關系呢? 假設:
加減乘除運算只遵循從左向右,從上至下,沒有優先級。 於是根據func函數變化出func2函數,替換if判斷表達式中的函數,運行,yes,出結果了,也就是假設正確。

告訴小伙伴答案后,小伙伴說正確了。
我們會心一笑。