题目:幻方构造,给你n*n的方形,在里面填上连续的数字,使得每行、每列和对角线上的数字和是m。
分析:数学、构造。幻方的构造方法已经完全被解决,直接利用公式求解即可。
幻方的幻和为:p =(n*n+1)* n / 2
如果 m = k*n + p 则题目要求幻方可以构造成功,否则无法构造。
幻方的构造可分成三种情况:(阶数n > 2)
a.奇数幻方构造
1.从第一行中间的位置开始,向一个对角线方向移动,连续填上数字;
2.如果越界就到对侧的边界相应位置;
3.如果对应位置有数字,就放在前一个数字的下方。
如图:
b.4k 形式的偶数
1.从上到下、从左到右,按顺序写下1到n*n;
2.分成4*4的小方形,每个小方形内部对角线上相应的数字交换。
如图:
c.4k+2 形式的偶数
1.把整个方形分成四个相同的小方形,编号A,B,C,D(从上到下,从左到右);
2.按照A,D,B,C的顺序分别构造奇数幻方;
3.AC交换操作:中间行中间列开始向右的k个交换AC元素;
除了中间行从中间列向前k个交换AC元素;
4.BD交换操作:每行从中间列开始向左的k-1列交换BD元素。
如图: 交换:
说明:注意处理过程中可能出现的溢出情况。
#include <iostream>
#include <cstdlib>
#include <cstring>
#include <cstdio>
using namespace std;
//奇数幻方
int matrix[105][105];
int visit[105][105];
int magic_square2m1( int n, int k, int x1, int y1 )
{
int count = 1,x = x1,y = y1+n/2;
while ( count <= n*n ) {
matrix[x][y] = k + count ++;
visit[x][y] = 1;
int xx = x-1;
if ( xx < x1 ) xx = x1+n-1;
int yy = y-1;
if ( yy < y1 ) yy = y1+n-1;
if ( visit[xx][yy] ) {
xx = x+1; yy = y;
}
x = xx; y = yy;
}
return n;
}
//4*m型幻方
int d[8][2] = {{0,0},{1,1},{2,2},{3,3},{0,3},{3,0},{1,2},{2,1}};
int magic_square4m( int n, int k )
{
int count = 1,x = 0,y = n/2;
for ( int i = 0 ; i < n ; ++ i )
for ( int j = 0 ; j < n ; ++ j )
matrix[i][j] = k + count ++;
for ( int i = 0 ; i < n ; i += 4 )
for ( int j = 0 ; j < n ; j += 4 )
for ( int k = 0 ; k < 8 ; ++ k )
matrix[i+d[k][0]][j+d[k][1]] = n*n+1-matrix[i+d[k][0]][j+d[k][1]];
return n;
}
//4*m+2型幻方
int magic_square4m2( int n, int k )
{
int v = n*n/4,u = n/2,m = (n-2)/4;
magic_square2m1( n/2, k+v*0, 0, 0 );
magic_square2m1( n/2, k+v*3, u, 0 );
magic_square2m1( n/2, k+v*2, 0, u );
magic_square2m1( n/2, k+v*1, u, u );
for ( int s,i = 0 ; i < u ; ++ i ) {
//交换AC
if ( i == u/2 ) s = i;
else s = 0;
for ( int j = 0 ; j < m ; ++ j )
swap( matrix[i][s+j], matrix[i+u][s+j] );
//交换BD
s = u+u/2;
for ( int j = 0 ; j < m-1 ; ++ j )
swap( matrix[i][s-j], matrix[i+u][s-j] );
}
return n;
}
//幻方测试
int ms_test( int n )
{
int sum1 = 0,sum2 = 0;
for ( int i = 0 ; i < n ; ++ i ) {
sum1 += matrix[i][i];
sum2 += matrix[i][n-1-i];
}
if ( sum1 != sum2 ) {
printf("构造失败!\n");
return 0;
}
for ( int i = 0 ; i < n ; ++ i ) {
int sum3 = 0,sum4 = 0;
for ( int j = 0 ; j < n ; ++ j ) {
sum3 += matrix[i][j];
sum4 += matrix[j][i];
}
if ( sum3 != sum1 || sum4 != sum1 ) {
printf("构造失败!\n");
return 0;
}
}
return 1;
}
int magic_square( int n, int k )
{
memset( visit, 0, sizeof(visit) );
if ( n%2 ) magic_square2m1( n, 0, 0, 0 );
else if ( n/2%2 ) magic_square4m2( n, 0 );
else magic_square4m( n, 0 );
if ( !ms_test( n ) ) {
printf("You can't be like Shahjahan!\n");
while (1);
return 0;
}
for ( int i = 0 ; i < n ; ++ i ) {
for ( int j = 0 ; j < n ; ++ j ) {
if ( j ) printf(" ");
printf("%10d",matrix[i][j]+k);
}
printf("\n");
}
return 1;
}
int main()
{
int n,m;
while ( scanf("%d%d",&n,&m) != EOF ) {
int line_sum = (n*n+1)*n/2;
if ( n == 2 || (m-line_sum)%n )
printf("You can't be like Shahjahan!\n");
else magic_square( n, (m-line_sum)/n );
printf("\n");
}
return 0;
}