累...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);
}