昨天我的小伙伴可能太无聊了,然后给我一道题:输入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(" "); 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(" "); 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(" "); 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,出结果了,也就是假设正确。
告诉小伙伴答案后,小伙伴说正确了。
我们会心一笑。