如何创建一个已经填充了一些数字的魔方?

时间:2012-12-15 15:43:28

标签: algorithm magic-square

我想这样做:我有一个矩阵N x N.它可以包含从1到n ^ 2的数字。该矩阵有几个单元格填充正数。我必须决定,这个已填充的矩阵可以是一个魔术矩阵(魔术方阵)。例如:

0 0 0 7 4

0 1 0 0 8

0 0 3 0 0

0 0 0 0 0

0 0 0 0 0 

我们可以从这个矩阵创建一个魔术方阵。 有没有算法来决定这个?你能推荐一下吗?谢谢!

2 个答案:

答案 0 :(得分:1)

我不确定它是否是最有效的方法,但你可以确定神奇常数:as

magic_constant = n*(n^2+1)/2

一旦你拥有了魔法常数,你可以像Sudoku拼图一样工作,在那里你可以确定哪些可能的值可以用于每个未填充的单元格,然后从具有最少可能值的单元格开始尝试每个值。使用数字填充单元格时,将更新其余未填充单元格的可能值。如果遇到单元格没有可能值的情况,则回溯。如果你没有可能性,那么答案就是“不”。如果你用完了未填充的细胞,那么答案就是“是”。

答案 1 :(得分:1)

有一种算法,而不仅仅适用于奇数行和列:

  1. 将1放在第一行的中间
  2. 向上移动一个单元格,然后向左移动一个单元格(您应该考虑循环矩阵)
  3. 在此单元格中添加越来越多的数字
  4. 只要达到n ^ 2
  5. ,请转到第2步

    这是一个C ++代码:

    #include <iostream>
    #include <iomanip>
    #define For(i,n) for(int i=0; i<n; i++)
    #define FOR(i,j,n) for(int i=0; i<n; i++) for(int j=0; j<n; j++)
    using namespace std;
    
    void print(int**, int);
    void calc(int**, int);
    void test(int**, int);
    
    int main()
    {
        int n;
        a:cout<<"Enter an odd number:";
        cin>>n;
        if (n % 2 == 0)
        {
            cout<<"You entered an even number!\n\n";
            goto a;
        }
        int** ary = new int*[n];
        For(i,n)
            ary[i] = new int[n];
    
        //Fill array entires with NULL
        FOR(i,j,n)
            ary[i][j] = NULL;   
    
        calc(ary,n);
        print(ary,n);
        test(ary,n);
    
        cin>>n;
    }
    void print(int** ary, int n)
    {
        cout<<endl;
        For(i,n)
        {
            For(j,n)
            {
                if (ary[i][j] == NULL) {cout<<"N  "; continue;}
            cout<<setw(4)<<ary[i][j];
            }
            cout<<endl;
        }
    }
    
    void calc(int** ary, int n)
    {
        int c=1, i=0, j=n/2;
        while(true)
        {
            if (ary[i][j] == NULL) ary[i][j] = c++;
            else
            {
                j++;
                i+=2;
                if (j == n) j = 0;
                if (i == n) i = 0;
                else if (i == n+1) i = 1;
                continue;
            }
            //cout<<"Filled ary["<<i<<"]["<<j<<"]\n";
            i--;
            j--;
            if (i < 0) i = n-1;
            if (j < 0) j = n-1;
            if (c> n*n) break;
        }
    }
    
    void test(int** ary, int n)
    {
        cout<<"\nTesting Sums. . .";
        int rSum = 0, cSum = 0, mDiagSum = 0, sDiagSum = 0;
        For(i,n)
        {
            For(j,n)
            {
                rSum += ary[i][j];
                cSum += ary[j][i];
                if (i == j) mDiagSum +=ary[i][j];
                if (n - 1 == i + j) sDiagSum += ary[i][j];
            }
            cout<<"\nSum of row #"<<i+1<<"= "<<rSum
                <<"\nSum of Column #"<<i+1<<"= "<<cSum;
            rSum = 0;
            cSum = 0;
        }
        cout<<"\nSum of main diagonal= "<<mDiagSum
            <<"\nSum of sub diagonal= "<<sDiagSum<<endl;
    }