(每一行每一列以及對角線之和都相等的方陣)
要求輸出1--n*n的魔方陣
(。。用的方法不好。。但是不知道哪裡錯了>_<)
#include
#include
int main()
{
int m[15][15],k,n,i,j;
for(n=2;n%2==0;)
{printf("enter your number:");
scanf("%d",&n);}
for(k=1,i=1,j=(n+1)/2;k<=n;k++)
{
m[i][j]=k;
if(i==1)
{
if(j==n)
{
l=m[n][1];
if(l==0) {m[n][1]=k+1;i=n;j=1;}
else {m[i+1][j]=k+1;i=i+1;}
}
else {
l=m[n][j+1];
if(l==0) {m[n][j+1]=k+1;i=n;j=j+1;}
else {m[i+1][j]=k+1;i=i+1;}
}
}
else
{
if(j==n)
{
l=m[i-1][1];
if(l==0) {m[i-1][1]=k+1;i=i-1;j=1;}
else {m[i+1][j]=k+1;i=i+1;}
}
}
l=m[i-1][j+1];
if(l==0) {m[i-1][j+1]=k+1;i=i-1;j=j+1;}
else {m[i+1][j]=k+1;i=i+1;}
}
for(i=1;i<=n;i++)
{ for(j=1;j<=n;j++)
printf("%d\t",m[i][j]);
printf("\n");
}
return 0;}
// app2.cpp : Defines the entry point for the console application.
//
#include "stdafx.h"
#include<stdio.h>
#include<math.h>
#define MAX 30
int a[MAX][MAX]; // 幻方矩陣
int n,s; // n:階數,s:幻方數
int x,y;
int i,j,k;
int total,m;
int ox,oy;
void main()
{
void odd(int m, int index);
void singleEven();
void FourXFour();
void doubleEven();
do
{
printf("Please input n(3<=n[<=17]):\t"); // 屏幕可顯示的最大階數為17
scanf("%d",&n);
if(n<3) continue; // 幻方最小階數
s=n*(pow(n,2)+1)/2; // 幻方數
printf("s=%d\n",s);
if(n%2==1){
// 奇階幻方
ox=oy=0;
odd(n,0); // 從1開始填寫n階幻方
}
else if(n%4==0)
{
// 雙偶階幻方
doubleEven();
}
else if(n%2==0)
{
// 單偶階幻方
singleEven();
}
// 輸出制作好的n階幻方
for(i=0;i<n;i++)
{
s=0;
for(j=0;j<n;j++)
s+=a[i][j],printf("%4d",a[i][j]);
printf("\t=%d\n",s);
}
fflush(stdin); // 清除多余或無效的輸入
}while(1);
}
/* 奇數階幻方
最經典的填法是羅伯特法(樓梯法),填寫方法是這樣:
把1(或最小的數)放在第一行正中;按以下規律排列剩下的n×n-1個數:
(1)每一個數放在前一個數的右上一格;
(2)如果這個數所要放的格已經超出了頂行那麼就把它放在底行,仍然要放在右一列;
(3)如果這個數所要放的格已經超出了最右列那麼就把它放在最左列,仍然要放在上一行;
(4)如果這個數所要放的格已經超出了頂行且超出了最右列,那麼就把它放在前一個數的下一行同一列的格內;
(5)如果這個數所要放的格已經有數填入,處理方法同(4)。
這種寫法總是先向“右上”的方向,象是在爬樓梯。
三階幻方:
8 1 6
3 5 7
4 9 2 */
// 解奇階幻方的通用模塊
// m 為階數
// index 為起始標識
void odd(int m, int index)
{
x=m/2;
y=0;
for(i=index+1;i<=index+pow(m,2);i++)
{
a[oy+y][ox+x]=i;
if(i%m==0) y++;
else x++,y--;
// else x++,y+=2; Hourse法
x=(x%m+m)%m;
y=(y%m+m)%m;
}
}
/* 單偶階幻方
n為偶數,且不能被4整除 (n=6,10,14,18,22……;n=4k+2,k=1,2,3,4,5……)
以n=10為例。這時,k=2
(1) 把方陣分為A,B,C,D四個象限,這樣每一個象限肯定是奇數階。
用樓梯法,依次在A象限,D象限,B象限,C象限按奇數階幻方的填法填數。
6階幻方第一步:
8 1 6 | 26 19 24
3 5 7 | 21 23 25
4 9 2 | 22 27 20
-------------------------
35 28 33 | 17 10 15
30 32 34 | 12 14 16
31 36 29 | 13 18 11
(2) 在A象限的中間行、中間格開始,按自左向右的方向,標出k格。
A象限的其它行則標出最左邊的k格。
將這些格,和C象限相對位置上的數,互換位置。
6階幻方第二步:
35* 1 6 | 26 19 24
3 32* 7 | 21 23 25
31* 9 2 | 22 27 20
-------------------------
8* 28 33 | 17 10 15
30 5* 34 | 12 14 16
4* 36 29 | 13 18 11
(3) 在B象限任一行的中間格,自右向左,標出k-1列。
(注:6階幻方由於k-1=0,所以不用再作B、D象限的數據交換)
將B象限標出的這些數,和D象限相對位置上的數進行交換,就形成幻方。
6階幻方:
35 1 6 | 26 19* 24
3 32 7 | 21 23* 25
31 9 2 | 22 27* 20
-------------------------
8 28 33 | 17 10* 15
30 5 34 | 12 14* 16
4 36 29 | 13 18* 11 */
void singleEven()
{
int temp;
// 步驟一
// A象限
ox=oy=0;
odd(n/2,pow(n/2,2)*0);
// D象限
ox=oy=n/2;
odd(n/2,pow(n/2,2)*1);
// B象限
ox=n/2,oy=0;
odd(n/2,pow(n/2,2)*2);
// C象限
ox=0,oy=n/2;
odd(n/2,pow(n/2,2)*3);
// 對已經按ADBC象限以奇階方式填充的幻方做處理
m=(n-2)/4;
for(i=0;i<n/2;i++)
{
// 步驟二
for(j=0;j<m;j++)
{
k=(i==n/4)?n/4+j:j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
// 步驟三
for(j=0;j<m-1;j++)
{
k=n/2+n/4+j;
temp=a[i][k];
a[i][k]=a[i+n/2][k];
a[i+n/2][k]=temp;
}
}
}
/* 雙偶階幻方
n為偶數,且能被4整除 (n=4,8,12,16,20……;n=4k,k=1,2,3,4,5……)
互補:如果兩個數字的和,等於幻方最大數和最小數的和,即 n*n+1,稱為互補。*/
/* 四階幻方
將數字從左到右、從上到下按順序填寫:
1 2 3 4
5 6 7 8
9 10 11 12
13 14 15 16
將對角線上的數字,換成與它互補的數字。
這裡,n×n+1 = 4×4+1 = 17;
把1換成17-1 = 16;
把6換成17-6 = 11;
把11換成17-11 = 6;
把16換成17-16 = 1;
……
換完後就是一個四階幻方。
16* 2 3 13*
5 11* 10* 8
9 7* 6* 12
4* 14 15 1* */
void FourXFour()
{
// 對已填寫數字的4階幻方進行對角線互補替換
for(i=0;i<4;i++)
{
a[oy+i][ox+i]=total-a[oy+i][ox+i];
a[oy+i][ox+(4-i-1)]=total-a[oy+i][ox+(4-i-1)];
}
}
/* 對於n=4k階幻方,我們先把數字按順序填寫。
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
寫好後,按4*4把它劃分成k*k個方陣。
因為n是4的倍數,一定能用4*4的小方陣分割。
1 2 3 4 | 5 6 7 8
9 10 11 12 | 13 14 15 16
17 18 19 20 | 21 22 23 24
25 26 27 28 | 29 30 31 32
---------------------------------
33 34 35 36 | 37 38 39 40
41 42 43 44 | 45 46 47 48
49 50 51 52 | 53 54 55 56
57 58 59 60 | 61 62 63 64
然後把每個小方陣的對角線上的數字換成互補的數字,就構成幻方。
64* 2 3 61*| 60* 6 7 57*
9 55* 54* 12 | 13 51* 50* 16
17 47* 46* 20 | 21 43* 42* 24
40* 26 27 37*| 36* 30 31 33*
---------------------------------
32* 34 35 29*| 28* 38 39 25*
41 23* 22* 44 | 45 19* 18* 48
49 15* 14* 52 | 53 11* 10* 56
8* 58 59 5*| 4* 62 63 1* */
void doubleEven()
{
// 填寫數字
x=y=0;
for(i=1;i<=pow(n,2);i++)
{
a[y][x]=i;
if(i%n==0) x=0,y++;
else x++;
}
total=1+pow(n,2); // 最大數和最小數的和
// 以 4x4 大小分割幻方
m=n/4;
x=y=0;
ox=oy=0;
for(k=1;k<=pow(m,2);k++)
{
// 對每個 4x4 幻方做對角互補替換
FourXFour();
if(k%m==0) ox=0,oy+=4;
else ox=k%m*4; // 轉移到下一個 4x4 幻方
}
}
Please input n(3<=n[<=17]): 3
s=15
8 1 6 =15
3 5 7 =15
4 9 2 =15
Please input n(3<=n[<=17]): 5
s=65
17 24 1 8 15 =65
23 5 7 14 16 =65
4 6 13 20 22 =65
10 12 19 21 3 =65
11 18 25 2 9 =65
Please input n(3<=n[<=17]):
源程序略有點問題,我順手修改了
出處
http://blog.csdn.net/cmutoo/article/details/5487157