魔方陣是一個古老的智力問題,它要求在一個m*m的矩陣中填入1~m*m的數字(m為奇數),使得每一行、每一列、每條對角線的累加和都相等,如下圖所示:
程序:
#include<stdio.h> #include<stdlib.h> #include<string.h> #define M 100 int main() { int a[M][M]; memset(a,0,sizeof(0)); int x,y,k,m; printf("輸入階數:"); scanf("%d",&m) ; while(!((m!=0)&&(m<M)&&(m%2!=0))) { printf("錯誤請重新輸入:"); scanf("%d",&m);//m = 3 } x=0; y=(m - 1)/2; a[x][y]=1; for(k=2;k<=m*m;k++){ x=(x-1+m)%m; y=(y-1+m)%m; if(a[x][y]==0){ a[x][y]=k; }else{ x=(x+2)%m; y=(y+1)%m; a[x][y]=k; } } printf("輸出的矩陣為:\n"); for(x=0;x<m;x++){ for(y=0;y<m;y++) printf("%d\t",a[x][y]); printf("\n"); } return 0; }
【解析】
首先:題目要求是在 m*m 階陣列中填入1,2,3.....m*m
其次:題目要保證每一行、每一列,對角線方向的所有的數的和相同
顯然,每個元素的選擇對全局的平衡有影響。那么,大平衡時,必然局部平衡,只有保證每個局部都平衡,才可以保證大局平衡
所以在分配中要 利用 “一多一少” 來滿足“∑各個方向的各個數”相同
以3*3矩陣為例:
——尋找3組元素構成中間序列————>
【1】
由於 5 是中間序列的中間的元素,為了達到平衡,必須選擇較小序列(1,2,3)中的最小值 1 和較大序列(7,8,9)中的最大值 9 ·
【2】
由於 6 是中間序列的偏大的元素,為了達到平衡,必須選擇較小序列(2,3)中的最小值 2 和較大序列(7,8)中的最小值 7,抵消 “偏大”帶來的影響
同理可得”3,4,8“
【3】
由於在構建過程中,每個局部都是平衡的,大小的影響都會被抵消,那么大平衡必然平衡
此時,所構成的矩陣中,列向 和 對角線方向 所填的數字滿足之和相同,即已平衡
橫向平衡如何實現??【所填數字之和相同】
接着,對超過邊界的進行 同向求模移位操作:
【比如,在上方右圖中,”7“在對角線序列(4,5,6) 中”4‘的 左1,下2,即從“4”開始,超過邊界的移位進行同方向求模移位,即:往左1,到“6”所在列 且 在“6”下方2單位處,再往下2,到“6”所在位置向下1單位處,如下圖】
綜上分析,完全可以對該序列先升序排序,然后取得中間序列,以中間序列數組為矩陣的對角線序列,再將兩邊的序列像千層餅一樣依次錯位層加,構造魔方陣
在上方層次疊加模型中,可以發現1的位置是永遠不會變的
【因為以中間序列為對角線元素時,從對角線底部到最上方以“1”開始的層列 所經過的橫向長度必然是 (m-1)/ 2 = (序列組數-1)/ 2 ,其中1代表中間序列,即,數字“1”所在的位置必然是 ( 0,(m-1)/2 )】
之后按照層次模型,從1開始往斜上方依次填充矩陣,超越矩陣范圍的,通過求模解決;當每一層次填充完畢后,求模操作中對應的x ,y 會返回至最開始的層次起點,那么就直接從起點 往右2,往下1 開始填充新的層次
流程圖如下:
制作整理不易,圖片均自制。如需轉載,請注明出處和作者。
如果有更清晰簡單的方法,歡迎評論~~