LinuxSir.cn,穿越时空的Linuxsir!

 找回密码
 注册
搜索
热搜: shell linux mysql
楼主: lordbyorn

求能计算所有方阵的程序

[复制链接]
发表于 2003-7-7 19:25:50 | 显示全部楼层
对方阵实在是没有研究,这二年把原来的数学底子都丢光了,
写了一个穷举的程序,太慢了,N=3还挺快,N=4就很慢,
重新想了一下,对N的每种取值使得和等于N*(N^2+1)/2的等式是有限的,如N=3有8种:
1  5  9
1  6  8
2  4  9
2  5  8
2  6  7
3  4  8
3  5  7
4  5  6
count: 8
能不能先计算出这些等式再计算方阵,
下面是求等式的程序,数值是用#define定义的,对每个N要重新编译。

  1. #include <stdio.h>

  2. #define N 3
  3. #define N2 9
  4. #define SUM 15
  5. #define FALSE 0
  6. #define TRUE 1
  7. #define WIDTH 2 /* 每一项输出的宽度 */

  8. int testsum(void);
  9. void print_a(void);
  10. void func(int, int);

  11. int a[N];
  12. int count;

  13. int main(void)
  14. {
  15.   func(0, 0);
  16.   printf("count: %d\n", count);

  17.   exit(0);
  18. }

  19. int
  20. testsum(void)
  21. {
  22.   int i, sum = 0;

  23.   for(i = 0; i < N; ++i)
  24.     sum += a[i];
  25.   if(sum != SUM)
  26.     return(FALSE);

  27.   ++count;
  28.   return(TRUE);
  29. }

  30. void
  31. print_a(void)
  32. {
  33.   int i;

  34.   for(i = 0; i < N; ++i)
  35.     printf("%*d ", WIDTH, a[i]);
  36.   printf("\n");
  37. }

  38. /* 递归调用,n表示项的位置,pi表示项的取值下限 */
  39. /* 对a进行穷举,如果用循环实现循环的嵌套层数等于N,就是a的项数,当N改变时
  40. * 难以实现,所以用递归。第一次调用n=0,对应于a的第一项,调用一次前进一项,
  41. * 对于N项,有N次递归。函数内用一个循环穷举一项的每种可能取值(我的穷举方阵
  42. * 就是这么实现的),对于这个程序,pi是为了使每一项的值都比前一项大,避免重复
  43. */
  44. void
  45. func(int n, int pi)
  46. {
  47.   int i;

  48.   for(i = pi; i < N2; ++i){
  49.     a[n] = i + 1;
  50.     if(n == N - 1){
  51.       if(testsum())
  52.         print_a();
  53.     }else
  54.       func(n + 1, i + 1);
  55.   }
  56. }
复制代码

下面是一些数据:
SUM: n*(n*n+1)/2
3: 15
4: 34
5: 65
6: 111
7: 175
8: 260
9: 369
10: 505

等式数目:
3: 8
4: 86
5: 1394
6: 32134
7以后我还没算,似乎比较大,能不能用数学方法推出等式的数目?
 楼主| 发表于 2003-7-7 20:08:08 | 显示全部楼层
过几天我有时间再做。

N=3 时有8个。
N=4时有7040个。
N=5时 ???
发表于 2003-7-7 20:26:18 | 显示全部楼层
改进一下,用命令行参数指定N:

  1. #include <stdio.h>

  2. #define FALSE 0
  3. #define TRUE 1
  4. #define WIDTH 2 /* 每一项输出的宽度 */

  5. int testsum(void);
  6. void print_a(void);
  7. void func(int, int);

  8. int N;
  9. int N2;
  10. int SUM;
  11. int *a;
  12. int count;

  13. int main(int argc, char *argv[])
  14. {
  15.   if(argc == 1){
  16.     fprintf(stderr, "usage: %s number\n", argv[0]);
  17.     exit(-1);
  18.   }

  19.   N = atoi(argv[1]);
  20.   N2 = N * N;
  21.   SUM = N * (N2 + 1) / 2;
  22.   a = (int *)malloc(N * sizeof(*a));

  23.   func(0, 0);
  24.   printf("count: %d\n", count);

  25.   free(a);
  26.   exit(0);
  27. }

  28. int
  29. testsum(void)
  30. {
  31.   int i, sum = 0;

  32.   for(i = 0; i < N; ++i)
  33.     sum += a[i];
  34.   if(sum != SUM)
  35.     return(FALSE);

  36.   ++count;
  37.   return(TRUE);
  38. }

  39. void
  40. print_a(void)
  41. {
  42.   int i;

  43.   for(i = 0; i < N; ++i)
  44.     printf("%*d ", WIDTH, a[i]);
  45.   printf("\n");
  46. }

  47. /* 递归调用,n表示a的位置,pi表示num的位置 */
  48. /* 对a进行穷举,如果用循环实现循环的嵌套层数等于N,就是a的项数,当N改变时
  49. * 难以实现,所以用递归。第一次调用n=0,对应于a的第一项,调用一次前进一项,
  50. * 对于N项,有N次递归。函数内用一个循环穷举一项的每种可能取值(我的穷举方阵
  51. * 就是这么实现的),对于这个程序,pi是为了使每一项的值都比前一项大,避免重复
  52. */
  53. void
  54. func(int n, int pi)
  55. {
  56.   int i;

  57.   for(i = pi; i < N2; ++i){
  58.     a[n] = i + 1;
  59.     if(n == N - 1){
  60.       if(testsum())
  61.         print_a();
  62.     }else
  63.       func(n + 1, i + 1);
  64.   }
  65. }
复制代码
 楼主| 发表于 2003-7-8 12:45:37 | 显示全部楼层
我昨天用了7个小时的时间运行我的程序(N=5),求出了大概10000个,我估计了一下,这只是全部结果的1/10000个。就是说硬盘都可能放不下。
N=10的时候,我是想也不敢想(全世界的硬盘也只能放下其中的小小一部分)。
我放心了,不用跳楼了。

只能找更加严格的条件了。
发表于 2003-7-8 14:38:50 | 显示全部楼层
Kill me?
Can not  work out a better method?
 楼主| 发表于 2003-7-8 17:00:20 | 显示全部楼层
最初由 hhkk 发表
Kill me?
Can not  work out a better method?


what?
totally don't understand.

can you give me a better method?

我给出的程序已经非常优化了。
用的是穷举的方法。
我的rang() 函数是最重要的,虽然很难理解。
这个函数让我保证只要能够填满方阵,一定是满足条件的。
我不用再写一个函数来检查。

再修改这个程序是不会增加太大的速度的。
发表于 2003-7-9 06:19:14 | 显示全部楼层
先贴一下我的完全穷举的程序,慢的很,N>=4的情况还是不要试了。

  1. #include <stdio.h>

  2. #define N 3
  3. #define N2 9
  4. #define SUM 15
  5. #define FALSE 0
  6. #define TRUE 1
  7. #define WIDTH 2

  8. int testsum(void);
  9. void print_a(void);
  10. void func(int);

  11. int a[N2];
  12. int num[N2];
  13. char line[(WIDTH + 1) * N + 1];
  14. int count;

  15. int main(void)
  16. {
  17.   int i;

  18.   memset(line, '-', (WIDTH + 1) * N);
  19.   line[(WIDTH + 1) * N] = '\0';
  20.   for(i = 0; i < N2; ++i)
  21.     num[i] = 0;

  22.   func(0);
  23.   printf("count: %d\n", count);

  24.   exit(0);
  25. }

  26. int
  27. testsum(void)
  28. {
  29.   int x, y, sum;


  30.   for(y = 0; y < N; ++y){
  31.     sum = 0;
  32.     for(x = 0; x < N; ++x)
  33.       sum += *(a + y * N + x);
  34.     if(sum != SUM)
  35.       return(FALSE);
  36.   }
  37.   for(x = 0; x < N; ++x){
  38.     sum = 0;
  39.     for(y = 0; y < N; ++y)
  40.       sum += *(a + y * N + x);
  41.     if(sum != SUM)
  42.       return(FALSE);
  43.   }
  44.   sum = 0;
  45.   for(x = 0, y = 0; x < N; ++x, ++y)
  46.     sum += *(a + y * N + x);
  47.   if(sum != SUM)
  48.     return(FALSE);
  49.   sum = 0;
  50.   for(x = N - 1, y = 0; y < N; --x, ++y)
  51.     sum += *(a + y * N + x);
  52.   if(sum != SUM)
  53.     return(FALSE);

  54.   ++count;
  55.   return(TRUE);
  56. }

  57. void
  58. print_a(void)
  59. {
  60.   int x, y, i;

  61.   for(y = 0; y < N; ++y){
  62.     for(x = 0; x < N; ++x)
  63.       printf("%*d ", WIDTH, *(a + y * N + x));
  64.     printf("\n");
  65.   }
  66.   printf("%s\n", line);
  67. }

  68. void
  69. func(int n)
  70. {
  71.   int i, sum = 0, val;

  72.   for(i = 0; i < N2; ++i){
  73.     if(num[i] == 0){
  74.       num[i] = 1;
  75.       *(a + n) = i + 1;
  76.       if(n == N2 - 1){
  77.         if(testsum())
  78.           print_a();
  79.       }else
  80.         func(n + 1);
  81.       num[i] = 0;
  82.     }
  83.   }
  84. }
复制代码

time了一下N=3时间是0.261
改进的程序回头再贴。
 楼主| 发表于 2003-7-9 11:50:49 | 显示全部楼层
libinary 你的程序要比我的好才有用啊。
我的N=4时是30s左右。
N=3时不用什么时间吧。
N=5时,不知道要几年时间。
发表于 2003-7-9 15:44:17 | 显示全部楼层
N必须是奇数吧?
 楼主| 发表于 2003-7-9 18:17:28 | 显示全部楼层
没有这样的规定
给你看几个:

  1. //////////////////////////////////
  2.     1    2   15   16
  3.    12   14    3    5
  4.    13    7   10    4
  5.     8   11    6    9
  6. *****************************************
  7.     1    2   15   16
  8.    13   14    3    4
  9.    12    7   10    5
  10.     8   11    6    9
  11. *****************************************
  12.     1    2   16   15
  13.    13   14    4    3
  14.    12    7    9    6
  15.     8   11    5   10
  16. *****************************************
  17.     1    3   14   16
  18.    10   13    4    7
  19.    15    6   11    2
  20.     8   12    5    9
  21. *****************************************
  22.     1    3   14   16
  23.    12   13    4    5
  24.    15    8    9    2
  25.     6   10    7   11
  26. *****************************************
  27.     1    3   14   16
  28.    15   13    4    2
  29.    10    6   11    7
  30.     8   12    5    9
  31. *****************************************
复制代码
您需要登录后才可以回帖 登录 | 注册

本版积分规则

快速回复 返回顶部 返回列表