《C程序設計(第四版)》 譚浩強的,第六章 第7題 有一個輸出 魔方陣的題,相信困惑了不少人,下面本文給予大家完整的解答。
所謂魔方陣即1-N*N個數排成一個n階矩陣,矩陣特點:每一行,每一列,對角線之和都等於相同的值。
下面根據資料總結得到:
1):奇數的魔方陣:
其數字排列規則如下:
1)將1填入第一行中間;
2)將每個數填在前一個數的右上方。
3)若該位置超出最上行,則改填在最下行的對應位置;
4)若該位置超出最右列,則該填在最左列的對應行位置;
5)若某元素填在第一行最右列,下一個數填在該數同列的下一行;
6)若某數已找到了填寫位置,但其已填了其他數據,則這個數應填在應該填的位置的同列的下一行位置。
自己的代碼如下:
#include<stdio.h> //此為求奇魔方陣的方法
#include<string.h>
int main()
{
int a[100][100],i,j,n,k,x,y;
printf("Enter n:\n");
while(scanf("%d",&n)!=EOF&&(n%2==1))
{
memset(a,0,sizeof(a));//將原始數組全部清0;必須清零
i=0;
j=n/2;
a[i][j]=1; //第一條
for(k=2;k<=n*n;k++)
{
x=i; //x,y記錄原來一個數的坐標
y=j;
i--;
j++;
if(i<0)i=n-1; //第二條
if(j>n-1)j=0; //第三條
if(a[0][n-1]!=0)//第四條 此條可以省略
{
a[1][n-1]=a[0][n-1]+1;
}
if(a[i][j]!=0)// 第五條
{
i=x+1;
j=y;
}
a[i][j]=k;
}
for(i=0;i<n;i++) //輸出此數組
{
for(j=0;j<n;j++)
printf("%4d",a[i][j]);
putchar('\n');
}
printf("Enter n:\n");
}
return 0;
}
2):雙偶數魔方陣:
所謂雙偶數即2*(2m)的數據,即4的整數倍,期排列特點如下:
1:把魔方陣分為上下左右4個n/2*n/2的小的方陣,左上角和右下角的n/2*n/2的小矩陣
2:偶行偶列,奇行奇列賦值為0,其余賦值為1;右上角和左上角的n/2*n/2的小矩陣,偶行奇列,奇行偶列賦值為0,其余賦值為1。
3:從魔方陣由左到右,由上到下開始賦值,賦值為從n*n到1,若遇到原來填入方陣中的0,則跳過此格;
4:從魔方陣由左到右,由上到下開始賦值,賦值為從1到n*n,若遇到原來填入方陣中的1,則跳過此格;
5:填完數據后則完成 雙偶數魔方陣;
我的代碼如下:
#include<stdio.h>//雙偶數的魔方陣 即4*m階 (m=1,2,3...)
#include<string.h>
int main()
{
int n,a[100][100],i,j,k;
while(scanf("%d",&n)!=EOF&&(n%4==0)&&n>0)
{
memset(a,0,sizeof(a));
for(i=0;i<n;i++)
for(j=0;j<n;j++)
{
if(i<n/2&&j<n/2||i>=n/2&&j>=n/2) //分別填入 0和1
if(i%2==0&&j%2==1||i%2==1&&j%2==0)
a[i][j]=1;
if(i>=n/2&&j<n/2||i<n/2&&j>=n/2)
if(i%2==0&&j%2==0||i%2==1&&j%2==1)
a[i][j]=1;
}
k=n*n;
for(i=0;i<n;i++) //填入n*n到1
for(j=0;j<n;j++)
{
if(a[i][j]==1)a[i][j]=k;
k--;
}
k=1;
for(i=0;i<n;i++)//填入1到n*n 並輸出魔方陣
{
for(j=0;j<n;j++)
{
if(a[i][j]==0)a[i][j]=k;
k++;
printf("%4d",a[i][j]);
}
putchar('\n');
}
}
}
3):單偶數魔方陣
所謂單偶數,即n=2*(2m+1)的數據,其數字排列特點如下:
1:將矩陣分為4個區,A、B、C、D區,其相對位置如下:
| A | C |
| D | B |
2:先把數字1到(n/2)*(n/2)按照奇數魔方陣的方法填入A中,然后把其每一個數據分別加上(n/2)*(n/2)填入到B中,再把B中的數據加上(n/2)*(n/2)填入到C中,再把C中的數據加上(n/2)*(n/2)填入到D中;
3:交換數字
需要交換的數字的規則:
1: 右邊兩個小方陣中大於(m+2)的列中所有的數字
2: 左邊兩個小方陣中(m+1,m+1)這一個方格的數字
3: 左邊兩個小方陣中除(m+1,1)格位之外,小於m+1的列中的所有數字
其中n=2*(2m+1);即m=(n-2)/4;
比如說n=6,即m=1這個例子;
先把這些數字做標記:如圖
只需要標記A區和C區數字即可,然后A區和D區數字對應交換,
C區和B區數字對應進行交換,此例C區沒有交換數字:
| 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 |
然后交換即得到單偶數魔方陣:如下圖:
| 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 |
代碼如下:
#include<stdio.h> // A C A、B、C、D四塊的相對位置
#include<string.h> // D B
#define M 100
void output(int a[][M],int n)
{
int i,j;
for(i=0;i<n;i++)
{
for(j=0;j<n;j++)
printf("%4d",a[i][j]);
printf("\n");
}
}
int main()
{
int a[100][100],i,j,k,x,y,n,m,t;
printf("請輸入單偶數n:\n");
while(scanf("%d",&n)!=EOF)
{
memset(a,0,sizeof(a));
//輸入A矩陣
a[0][n/2/2]=1;
i=0;
j=n/2/2;
for(k=2;k<=(n/2*n/2);k++)
{
x=i;
y=j;
i--;
j++;
if(i<0)i=n/2-1;
if(j>n/2-1)j=0;
if(a[i][j]!=0)
{
i=x+1;
j=y;
}
a[i][j]=k;
}
//輸入B矩陣
for(i=n/2;i<n;i++)
for(j=n/2;j<n;j++)
{
a[i][j]=a[i-n/2][j-n/2]+(n/2)*(n/2);
}
//C...
for(i=0;i<n/2;i++)
for(j=n/2;j<n;j++)
{
a[i][j]=a[i+n/2][j]+(n/2)*(n/2);
}
//D...
for(i=n/2;i<n;i++)
for(j=0;j<n/2;j++)
{
a[i][j]=a[i-n/2][j+n/2]+(n/2)*(n/2);
}
//交換數字
//A和D換 因為n=2*(2m+1),所以m=(n-2)/4
//步驟1: 交換第(m+1,m+1)格
m=(n-2)/4;
t=a[m][m];
a[m][m]=a[m+n/2][m];
a[m+n/2][m]=t;
//2:交換除了(m+1,1)格以外的小於m+1的列
for(i=0;i<n/2;i++)
for(j=0;j<n/2;j++)
{
if(j<m)
{
if(i==m&&j==0)continue;
t=a[i][j];
a[i][j]=a[i+n/2][j];
a[i+n/2][j]=t;
}
}
//C和B的交換
for(i=0;i<n/2;i++)
for(j=n/2;j<n;j++)
{
if(j>n/2+m+1)
{
t=a[i][j];
a[i][j]=a[i+n/2][j];
a[i+n/2][j]=t;
}
}
output(a,n); //輸出魔方陣
printf("請輸入單偶數n:\n");
}
return 0;
}
好了,這就是1--n階的魔方陣,當然魔方陣的排列規則有很多,還可以構造魔方陣,只要記住其中一種方法就可以了,若要看整合的代碼,並帶有檢測是否為魔方陣的環節,請看下篇魔方陣(2),這就是魔方陣的全面解答,與大家分享,此文若有有不足之處或錯誤請指正;
