數據結構設計——魔方陣【絕對整理清楚】


魔方陣是一個古老的智力問題,它要求在一個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 開始填充新的層次

 

流程圖如下:

 

 

 

 

制作整理不易,圖片均自制。如需轉載,請注明出處和作者。

如果有更清晰簡單的方法,歡迎評論~~


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM