输入1~8,每个数字不重复

昨天我的小伙伴可能太无聊了,然后给我一道题:输入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,出结果了,也就是假设正确。

告诉小伙伴答案后,小伙伴说正确了。

我们会心一笑。

 

posted @ 2015-08-19 14:13  牧师/preacher  阅读(2306)  评论(3编辑  收藏  举报