三种幻方输出方法

来源:洛谷Scarlet大佬
Scarlet大佬的github
推导过程在文件里搜magic就有,也有大佬的其他算法随笔

以下是总结代码

#include <bits/stdc++.h>
using namespace std;
typedef long long int LL;
const int N=1e3+10;
LL n,magic[N][N];

//首先,对于所有幻方,其特征值为 n*(n*n+1)/2

//奇数阶幻方
void magic_odd(int n)
{
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<(i+j+n-(n+3)/2)%n*n+(i+j*2-2)%n+1<<" ";
        }
        cout<<endl;
    }
}

//双偶数阶幻方(n要是4的倍数)
void magic4(int n)
{
    LL total=n*n+1;
	for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=n;j++)
		{
			magic[i][j]=(i-1)*n+j;
			if((i%4)/2==(j%4)/2)
			{
				magic[i][j]=total-magic[i][j];
			}
			cout<<magic[i][j]<<" ";
		}
		cout<<endl;
	}
}

//单偶数阶幻方
void magic2(int n)
{
    int p=n/2,p2=p*p;

    //先生成奇数阶幻方
    for(int i=1;i<=p;i++)
    {
        for(int j=1;j<=p;j++)
        {
            magic[i][j]=(i+j+p-(p+3)/2)%p*p+(i+j*2-2)%p+1;
        }
    }
    
    //构建分块矩阵
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            int ii=(i-1)/p;
            int jj=(j-1)/p;
            int offset=0;
            
            //    0   |   1
            //0|  0       2*p2
            //1| 3*p2     p2
            if(ii==0&&jj==0) offset=0;
            else if(ii==0&&jj==1) offset=2*p2;
            else if(ii==1&&jj==0) offset=3*p2;
            else if(ii==1&&jj==1) offset=p2;

            int oi=(i-1)%p+1;
            int oj=(j-1)%p+1;
            magic[i][j]=magic[oi][oj]+offset;
        }
    }

    //前k列的上下两半互换
    int k=(n-2)/4;
    for(int j=1;j<=k;j++)
    {
        for(int i=1;i<=p;i++)
        {
            swap(magic[i][j],magic[i+p][j]);
        }
    }

    //将k+1行上 1 ~ 2*k 列 与对应的 +p 行交换
    for(int j=1;j<=2*k;j++)
    {
        swap(magic[k+1][j],magic[k+1+p][j]);
    }

    //将k+1+n列 往左数共k-1列 的上下对换
    int cnt=k-1,j=k+1+n;
    while(cnt--)
    {
        for(int i=1;i<=p;i++)
        {
            swap(magic[i][j],magic[i+p][j]);
        }
        j--;
    }

    
    for(int i=1;i<=n;i++)
    {
        for(int j=1;j<=n;j++)
        {
            cout<<setw(3)<<magic[i][j]<<" ";
        }
        cout<<endl;
    }
}

int main() {
	cin>>n;
	magic2(n);
	return 0;
}
posted @ 2025-03-10 00:50  石磨豆浆  阅读(22)  评论(0)    收藏  举报