幻方(UVa 10087 - The Tajmahal of ++Y2k)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/mobius_strip/article/details/25649769

题目:幻方构造,给你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;
}


猜你喜欢

转载自blog.csdn.net/mobius_strip/article/details/25649769