幻方

累...CSDN老是写不上来...如果下次还这样,我就换博 

#include <stdio.h>
#include <windows.h>


int used[17] = {0};
int nMagicSquares[16] = {0} ;

                                         
#define IsEqu(i,n) (used[i[n]] ? false : true)
#define IsValid(nElement) ((nElement)<=16 && (nElement)>=1 ? true : false)

 

#define DisplayMagicSquares(nNumMagicSquares) /
            printf("No.%d/n",nNumMagicSquares);/
            printf("-------------/n");/
            printf("%2d %2d %2d %2d/n",nMagicSquares[0],nMagicSquares[8],nMagicSquares[9],nMagicSquares[1]);/
            printf("%2d %2d %2d %2d/n",nMagicSquares[12],nMagicSquares[2],nMagicSquares[3],nMagicSquares[13]);/
            printf("%2d %2d %2d %2d/n",nMagicSquares[14],nMagicSquares[4],nMagicSquares[6],nMagicSquares[15]);/
            printf("%2d %2d %2d %2d/n",nMagicSquares[5],nMagicSquares[10],nMagicSquares[11],nMagicSquares[7]);/
            printf("/n/n");/
            system("pause")


 /*

 
inline bool IsEqu(int nSquaresSection[],int nSize)
{
    return used[nSquaresSection[nSize]]? false : true;
}

inline bool IsValid(int nElement)
{
    return (nElement<=16 && nElement>=1) ? true : false;
}

inline void    DisplayMagicSquares(int nNumMagicSquares)
{                               
    printf("No.%d/n",nNumMagicSquares);
    printf("-------------/n");
    printf("%2d %2d %2d %2d/n",nMagicSquares[0],nMagicSquares[8],nMagicSquares[9],nMagicSquares[1]);
    printf("%2d %2d %2d %2d/n",nMagicSquares[12],nMagicSquares[2],nMagicSquares[3],nMagicSquares[13]);
    printf("%2d %2d %2d %2d/n",nMagicSquares[14],nMagicSquares[4],nMagicSquares[6],nMagicSquares[15]);
    printf("%2d %2d %2d %2d/n",nMagicSquares[5],nMagicSquares[10],nMagicSquares[11],nMagicSquares[7]);
    printf("/n/n");
}
*/


int  main()
{
    int i[16];
    int j = 0;

    DWORD dwStart = GetTickCount();
   
     // fix i[0] and i[1]
    for( i[0]=1;i[0]<=16;i[0]++)
    {
      
        used[i[0]] = i[0];
        nMagicSquares[0] = i[0];
        for(i[1]=1;i[1]<=16;i[1]++)
        {            
            if(!IsEqu(i,1)) continue;
            nMagicSquares[1] = i[1];
            used[i[1]] = i[1];
           
            // fix i[2]
            for( i[2]=1;i[2]<=16;i[2]++)
            {               
                if(!IsEqu(i,2)) continue;
                nMagicSquares[2] = i[2];
                used[i[2]] = i[2];
               
                // fix i[3]
                for(i[3]=1; i[3]<=16; i[3]++)
                {
                   
                    if(!IsEqu(i,3)) continue;
                    nMagicSquares[3] = i[3];
                    used[i[3]] = i[3];
                   
                    // fix i[4]
                    for(
                        i[4]=max(1,18 - i[1] - i[3]);
                        i[4]<=min(16,33 - i[1] - i[3]);
                        i[4]++
                    )
                    {                       
                        if(!IsEqu(i,4)) continue;
                        nMagicSquares[4] = i[4];
                        used[i[4]] = i[4];
                       
                        // fix i[5]: the sum of diagonal equ 34
                        i[5] = 34 - i[1] -i[3] - i[4];
                        if (!IsEqu(i,5) || !IsValid(i[5])) goto __Next_M_4;
                        nMagicSquares[5] = i[5];
                        used[i[5]] = i[5];
                       
                        // fix i[6]
                        for(
                            i[6]=max(1,18 - i[0] - i[2]);
                            i[6]<=min(16,33 - i[0] - i[2]);
                            i[6]++
                        )
                        {                      
                            if(!IsEqu(i,6)) continue;
                            nMagicSquares[6] = i[6];
                            used[i[6]] = i[6];
                           
                            // fix i[7]: the sum of diagonal equ 34
                            i[7] = 34 - i[0] - i[2] - i[6];
                            if (!IsEqu(i,7) || !IsValid(i[7])) goto __Next_M_6;
                            nMagicSquares[7] = i[7];
                            used[i[7]] = i[7];
                           
                            // fix i[8]
                            for(
                                i[8]=max(max(1,18 - i[2] - i[4]),18 - i[0]-i [1]);
                                i[8]<=min(min(16,33 - i[2] - i[4]),33 - i[0]-i [1]);
                                i[8]++
                            )
                            {
                              
                                if(!IsEqu(i,8)) continue;
                                nMagicSquares[8] = i[8];
                                used[i[8]] = i[8];
                               
                                // fix i[9]/[10]/[11]: the sum of row and line equ 34
                                i[9] = 34 - i[0] - i[8] - i[1];      
                                if (!IsEqu(i,9) || !IsValid(i[9])) goto __Next_M_8;
                                nMagicSquares[9] = i[9];
                                used[i[9]] = i[9];
                               
                                i[10] = 34 - i[8] - i[2] - i[4];
                                if (!IsEqu(i,10) || !IsValid(i[10])) goto __Next_M_9;
                                nMagicSquares[10] = i[10];
                                used[i[10]] = i[10];
                               
                                i[11] = 34 - i[9] - i[3] - i[6];
                                if (!IsEqu(i,11) || !IsValid(i[11])) goto __Next_M_10;
                                nMagicSquares[11] = i[11];
                                used[i[11]] = i[11];
                               
                                // fix i[12]
                                for(
                                    i[12]=max(max(1,18 - i[0] - i[5]),18 - i[2]-i [3]);
                                    i[12]<=min(min(16,33 - i[0] - i[5]),33 - i[2]-i [3]);
                                    i[12]++
                                )
                                {
                                    if(!IsEqu(i,12)) continue;
                                    nMagicSquares[12] = i[12];
                                    used[i[12]] = i[12];
                                   
                                   
                                    // fix i[9]/[10]/[11]: the sum of row and line equ 34
                                    i[13] = 34 - i[12] - i[2] - i[3];
                                    if (!IsEqu(i,13) || !IsValid(i[13])) goto __Next_M_12;
                                    nMagicSquares[13] = i[13];
                                    used[i[13]] = i[13];
                                   
                                    i[14] = 34 - i[0] - i[12] - i[5];
                                    if (!IsEqu(i,14) || !IsValid(i[14])) goto __Next_M_13;
                                    nMagicSquares[14] = i[14];
                                    used[i[14]] = i[14];
                                   
                                    i[15] = 34 - i[14] - i[4] - i[6];
                                   if ( !IsEqu(i,15) || !IsValid(i[15])) goto __Next_M_14;
                                    nMagicSquares[15] = i[15];
                                    //used[i[15]] = i[15];
                                   
                                    // Get a magic squares
                                    j++;
                                    DisplayMagicSquares(j);

                                    //used[i[15]] = 0;
__Next_M_14:
                                    used[i[14]] = 0;
__Next_M_13:
                                    used[i[13]] = 0;
__Next_M_12:
                                    used[i[12]] = 0;
                                } // end i[7](i[12]) cycle
                                used[i[11]] = 0;
__Next_M_10:
                                used[i[10]] = 0;
__Next_M_9:
                                used[i[9]] = 0;
__Next_M_8:
                                used[i[8]] = 0;
                            }// end i[6](i[8]) cycle
                            used[i[7]] = 0;
__Next_M_6:                           
                            used[i[6]] = 0;
                        }// end i[5](i[6]) cycle
                        used[i[5]] = 0;
__Next_M_4:                      
                        used[i[4]] = 0;
                    }// end i[4](i[4]) cycle
                    used[i[3]] = 0;                    
                }// end i[3](i[3]) cycle
                used[i[2]] = 0;
            }// end i[2](i[2]) cycle
            used[i[1]] = 0;     
            }//end i[1](i[2]) cycle
            used[i[0]] = 0;
    }// end i[0](i[0]) cycle 

   printf("Count is %d/n",j);

   printf("Time escape : %d/n",GetTickCount()-dwStart);

    return 1;
}

 

--------------------------------------------------------

/* Author     : Lenus Margin
 * Data       : 2007.08.03 -- 2007.08.05
 * Description: save as "Readme.txt".
 */

/* 请最大化查看 */

Homework -- MagicSquares

* 要求计算出所有四阶幻方的个数
* 并打印出来

完成情况,代码见 MagicSquares.cpp

原理:采用最白痴的办法一个一个的数值进行添加,首先确定八个元素,利用此八个元素和幻方的特性得到其他八个元素。

Step1:首先用循环确定5个不位置的元素(MagicSquares[x]简单记为M[x],以下同),推出第六个元素M5
+----+----+----+----+
| M0 |    |    | M1 |
+----+----+----+----+
|    | M2 | M3 |    |
+----+----+----+----+
|    | M4 |    |    |
+----+----+----+----+
| ?  |    |    |    |      // 利用幻方的特性得到左下角元素M5。
+----+----+----+----+

      
Step2:确定元素M6,推出第八个元素M7
+----+----+----+----+
| M0 |    |    | M1 |
+----+----+----+----+
|    | M2 | M3 |    |
+----+----+----+----+
|    | M4 | M6 |    |
+----+----+----+----+
| M5 |    |    |  ? |
+----+----+----+----+


Step3:确定第九个元素M8,推出第十、十一、十二个元素M9,M10,M11
+----+----+----+----+ 
| M0 | M8 |  ? | M1 | 
+----+----+----+----+
|    | M2 | M3 |    |
+----+----+----+----+
|    | M4 | M6 |    |
+----+----+----+----+
| M5 |  ? |  ? | M7 |
+----+----+----+----+

Step4:确定第十三个元素M12,推出十四、十五、十六个元素M13,M14,M15
+----+----+----+----+
| M0 | M8 | M9 | M1 |
+----+----+----+----+
| M12| M2 | M3 |  ? |
+----+----+----+----+
|  ? | M4 | M6 |  ? |
+----+----+----+----+
| M5 | M10| M11| M7 |
+----+----+----+----+

最后得到一个幻方,按照下面的顺序进行输出

+----+----+----+----+
| M0 | M8 | M9 | M1 |
+----+----+----+----+
| M12| M2 | M3 | M13|
+----+----+----+----+
| M14| M4 | M6 | M15|
+----+----+----+----+
| M5 | M10| M11| M7 |
+----+----+----+----+


小结:四阶幻方规律很强,使用此方法,代码的复杂度很大。不能用于五阶。方法比较笨拙,但是效果还行!

输出结果对比:

1.使用输出结果的printf语句:5.344秒
2.不使用输出结果的printf语句:3.515秒
3.如果使用宏而不是inline语句,得到的时间会更少。

问题:我发现VC编译器并不对所有的inline进行展开,函数消耗了部分的时间。而如何将一个for语句使用宏去定义是我没有解决的问题。

---------------------------------------

牛人的程序

#include   <stdio.h>  
#include   <stdlib.h>
#include <windows.h>

int   p[100][4],l=0,t=0;  
int   q[4],p4[30][4];  
long  total=0;  
int   board[4][4];  
unsigned   long   s[100];  

void   finalJudge()  
{  
 int   i,j,k,m,x,y;  
 for(i=0;i<24;i++)  
 {  
  for(j=0;j<24;j++)  
  {  
   for (k=0,x=0,y=0;k<4;k++)  
   {  
    x+=board[p4[i][k]][p4[j][k]];  
    y+=board[p4[i][3-k]][p4[j][k]];  
   }  
   if   (x==34   &&   y==34)  
   {  
    total++;  
    for   (k=0;k<4;k++,printf("/n"))  
     for   (m=0;m<4;m++)  
      printf("%2d  ",board[p4[i][k]][p4[j][m]]);  
     printf("/n");
     getchar();
   }  
  }  
 }     
}  

void   construct()  
{  
 int   i,j,k,m,x[4];  
 for   (i=0;i<24;i++)  
 {  
  for   (j=0;j<24;j++)  
  {  
   for   (k=0;k<4;k++)  
   {  
    x[k]=34-p[q[0]][k]-p[q[1]][p4[i][k]]-p[q[2]][p4[j][k]];  
    board[3][k]=x[k];  
    if   (x[k]<1   ||   x[k]>16   ||   !((1l<<(x[k]-1))   &   s[q[3]]))   break;  
    for   (m=0;m<k;m++)  
     if   (x[m]==x[k])   break;  
     if   (m<k)   break;  
   }  
   if   (k==4)  
   {  
    for   (k=0;k<4;k++)  
     board[0][k]=p[q[0]][k];  
    for   (k=0;k<4;k++)  
     board[1][k]=p[q[1]][p4[i][k]];  
    for   (k=0;k<4;k++)  
     board[2][k]=p[q[2]][p4[j][k]];  
    finalJudge();  
   }  
  }  
 }  
}  

void   make(int   b,int   deep)         // 递归调用
{  
 int   i,j,sum;  
 if   (deep>=4)                      // 深度为4
 {  
  for   (j=0,sum=0;j<4;j++)  
   sum+=(p[l+1][j]=p[l][j]);  // 每次的数组应该为34
  if   (sum==34)  
  {  
   for   (j=0,s[l]=0;j<4;j++)  
    s[l]+=1l<<(p[l][j]-1);  
   l++;                        // 得到一组可使用的4元素数组
  }  
  return;  
 }                                  
 for   (i=b;i<=16;i++)               // i = b 就能保证不重复取数
 {                                   // 循环16次得到所有的可匹配数组
  p[l][deep]=i;  
  make(i+1,deep+1);  
 }  
}  

void   makeP44(int   deep){  
 int   i,j,flag;  
 if   (deep>=4)  
 {  
  for   (j=0;j<4;j++)  
   p4[t+1][j]=p4[t][j];  
  t++;  
  return;  
 }  
 for   (i=0;i<4;i++)                 // 建立4x4表格
 {  
  p4[t][deep]=i;  
  flag=1;  
  for   (j=0;j<deep;j++) if   (p4[t][j]==i)   flag=0;  
  if   (flag)   makeP44(deep+1);  
 }  
}  

void   solve(int   b,int   deep)  
{  
 int   i,j,flag;  
 if   (deep>=4)  
 {  
  construct();  
  return;  
 }  
 for   (i=b;i<l;i++)  
 {  
  q[deep]=i;  
  flag=1;  
  for   (j=0;j<deep;j++) if(s[q[j]] & s[i]) flag=0;  
  if   (flag)   solve(i+1,deep+1);  
 }  
}  

void main()
{  
 int uBegin = GetTickCount();
 freopen("1.txt","w",stdout);  
 make(1,0);  
 makeP44(0);  
 solve(0,0); 
 int uEnd = GetTickCount();
 printf("%ld/n",uEnd - uBegin);  
}
--------------------------

/* Author     : Lenus Margin
 * Data       : 2007.08.07 -- 2007.08.08
 * Description: save as "Readme.txt".
 */

/* 请最大化查看 */

/* 申明: 网上下来的程序,不是我写出来的。只是把四阶改成了五阶,还没有跑完过,所以还不能肯定

下面的程序一定对。
         水平太菜不知道如何优化。大家有空看看吧!

4.cpp   -- 原网上下载的4阶程序
square.cpp      -- 自己修改后的5阶程序
*/


程序原理:利用空间换时间

-------------------------------------------------------------

1.make(0函数

功能:不重复的得到所有相加为65的5个数

原理:利用类似构造一个树的原理,对每一个分支进行判断是否等于65,得到数组p
     同时利用一个对应大小(大概是1390多)的数组s保存此5个数的特征

技巧:利用bit位进行数的特征表现:例如:1 2 13 24 25 分别对应 1 2 13 24 25位,即1100000000000011b

= 0C003H
     这样比较的时候只要与一下就可以判断是否相等了。

-------------------------------------------------------------

2.make55()函数

功能:得到所有5阶全排列

原理:使用0-4保存到相应大小的树组,作为排列顺序,得到数组p5

-------------------------------------------------------------

3.solve()函数

功能: 确定5个不相同的行

原理: 利用make函数得到5个数的数组p和特征树组s,从p中抽取5个
      if(s[q[j]]   &   s[i])   flag=0; 利用标志为确定下标,得到一个q树组

-------------------------------------------------------------

4.construct()函数

功能: 构造列元素

原理: 利用solve函数中得到的5个数组(q[5]),再利用make55函数中得到的全排列的下标确定每列上的5个

元素和为65
      最后得到一个5x5的方阵board[5][5],它的行和列相加都为65

技巧: 随机排列前四行的元素,每一次排列后计算第五行的元素进行,并判断是否合法(if(x[k]<1||x

[k]>16||!((1l<<(x[k]-1))&s[q[3]])))
      *个人认为这个地方还可以优化一下*

-------------------------------------------------------------

5.finalJudge()函数

功能: 判断斜边及输出

原理: 利用从make55中得到的全排列下标数组p5,进行和列的全排列,得到一个新的方阵,判断斜边后决

定是否输出

-----------------------------------

#include <stdio.h>
#include <windows.h>

int   p[1400][5],l=0,t=0;   // p不重复的和为65的5个数 l和t分别为p的下标                                       
int   q[5],p5[130][5];      // q不重复的5行p,p5为5x5的方阵全排列的下标
DWORD   total=0;            // 幻方数
int   board[5][5];          // 幻方
unsigned   long   s[1400];  // p(不重复的和为65的5个数)的特征

inline void   finalJudge()  
{  
    int   i,j,k,m,x,y;  
    for   (i=0;i<120;i++)                                       // 控制行的全排列 
    {  
        for   (j=0;j<120;j++)                                   // 控制列的全排列  
        {  
            for   (k=0,x=0,y=0;k<5;k++)  
            {  
                x+=board[p5[i][k]][p5[j][k]];                   // 计算斜边和
                y+=board[p5[i][4-k]][p5[j][k]];  
            }  
            if   (x==65   &&   y==65)                           // 成功输出 
            {  
                total++;  
                for   (k=0;k<5;k++,printf("/n"))  
                    for   (m=0;m<5;m++)  
                        printf("%2d   ",board[p5[i][k]][p5[j][m]]);  
                    printf("No.%d/n",total);
            } 
           
        }  
    }  
   
}  

inline void   construct()  
{  
    int   i,j,k,m,n,x[5];  
    for   (i=0;i<120;i++)                                       // i,j 控制第二第三行的位子
    {  
        for   (j=0;j<120;j++)                                   // 120 = 5!
        {  
            for   (n=0;n<120;n++)  
            { 
                for   (k=0;k<5;k++)  
                {                                               // 计算第五行的元素
                    x[k]=65-p[q[0]][k] - p[q[1]][p5[i][k]] - p[q[2]][p5[j][k]] - p[q[3]][p5[n][k]];     
                    if   (x[k]<1   ||   x[k]>25   ||   !((1l<<(x[k]-1))   &   s[q[4]]))   break; 
                   
                    board[4][k]=x[k]; 
                 
                    for   (m=0;m<k;m++)                         // 判断第五行的元素是否自己相等
                        if   (x[m]==x[k])   break;              // 这里应该可以优化
                    if   (m<k)   break;  
                }  
                if   (k==5)                                     // 得到一个列和行和都为65的方阵
                {  
                    for   (k=0;k<5;k++)  
                        board[0][k]=p[q[0]][k];  
                    for   (k=0;k<5;k++)  
                        board[1][k]=p[q[1]][p5[i][k]];  
                    for   (k=0;k<5;k++)  
                        board[2][k]=p[q[2]][p5[j][k]];
                    for   (k=0;k<5;k++)  
                        board[3][k]=p[q[3]][p5[n][k]];  
                    finalJudge();                               // 判断这个board的斜边
                }  
            }
        }  
    }  
}  

inline void   make(int   b,int   deep)  
{  
    int   i,j,sum;  
    if   (deep>=5)  
    {  
        for   (j=0,sum=0;j<5;j++)  
            sum+=(p[l+1][j]=p[l][j]);                            // 因为i=b,所以需要下一个数组的前位赋上原来的值
        if   (sum == 65)  
        {  
            for   (j=0,s[l]=0;j<5;j++)  
                s[l]+=1l<<(p[l][j]-1);                           // 得到这组数字的标志位0 - 32bit 对应1 - 33的自然数
            l++;  
        }  
        return;  
    }  
    for   (i=b;i<=25;i++)                                       //  1 - 25 的循环
    {  
        p[l][deep]=i;  
        make(i+1,deep+1);  
    }  
}  

inline void   makep55(int   deep){  
    int   i,j,flag;  
    if   (deep>=5)  
    {  
        for   (j=0;j<5;j++)  
            p5[t+1][j]=p5[t][j];                                // 因为i=b,所以p[l+1][j] = p[l][j]
        t++;  
        return;  
    }  
    for   (i=0;i<5;i++)  
    {  
        p5[t][deep]=i;  
        flag=1;  
        for   (j=0;j<deep;j++)  
            if   (p5[t][j]==i)   flag=0;                        // 利用flag 得到不同的下标 0 1 2 3 4 5
            if   (flag)   makep55(deep+1);  
    }  
}  

inline void   solve(int   b,int   deep)  
{  
    int   i,j,flag;  
    if   (deep>=5)  
    {  
        construct();  
        return;  
    }  
    for   (i=b;i<l;i++)  
    {  
        q[deep]=i;                                               // 保存着完全不重复的5个横列在p中的下标 
        flag=1;  
        for   (j=0;j<deep;j++)  
            if   (s[q[j]]   &   s[i])   flag=0;                  // 如果取到两个相等的p的元素,那么 s[q[j]]&s[i] == 1    
            if   (flag)   solve(i+1,deep+1);  
    }  
}  

void main(){  
    /*freopen("1.txt","w",stdout);*/  
    DWORD dwStart;
    dwStart = GetTickCount();

    make(1,0);  
    makep55(0);  
    solve(0,0);  
 
    printf("total=%ld/n",total);  
    printf("The time esrape %d/n",GetTickCount()-dwStart);
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值