Day2 神奇矩阵

神奇矩阵

如图所示,所谓神奇矩阵就是将 1 1 1 ~ 9 9 9 9 9 9 个数排成 3 3 3 3 3 3 列,使其行、列、对角线上 3 3 3 个数之和相同。试输出所有神奇矩阵的排序方式。
如图所示

输入格式

无输入。

输出格式

输出所有神奇矩阵的排序方式,每种之间空一行。

解题思路

这道题最容易想到的算法是枚举法,但其时间复杂度高达 O ( n 3 ) O(n^3) O(n3)。伪代码如下所示:

for(int i=159; i<=951; i++)//枚举第1行数
	for(int j=159; j<=951; j++)//枚举第2行数
		for(int j=159; k<=951; k++)//枚举第3行数
		{
			将i、j、k这3个三位数拆成9个一位数
			判断3行上的3个数之和是不是15
			判断3列上的3个数之和是不是15
			判断两2对角线上的3个数之和是不是15
			判断9个数是否重复
		}

进一步的优化是将每一行看作一个三位数,首先找出所有三位上的数之和为 15 15 15 ,且把三位上的各不相同的三位数一次存入数组 a r y [ ] ary[] ary[]

再通过枚举的方法从 a r y [ ] ary[] ary[] 中任取 3 3 3 个数,为方便起见,将放在第 1 1 1 行的数编号为 1 1 1 ,将放在第 2 2 2 行的数编号为 2 2 2 ,将放在第 3 3 3 行的数编号为 3 3 3 ,显然这 3 3 3 行数共有 6 6 6 种排列方式,分别为 ( 1 , 2 , 3 ) (1,2,3) (1,2,3) ( 1 , 3 , 2 ) (1,3,2) (1,3,2) ( 2 , 1 , 3 ) (2,1,3) (2,1,3) ( 2 , 3 , 1 ) (2,3,1) (2,3,1) ( 3 , 1 , 2 ) (3,1,2) (3,1,2) ( 3 , 2 , 1 ) (3,2,1) (3,2,1)

因为从 3 3 3 行数中取 1 1 1 行数放在第 1 1 1 行有 3 3 3 种方法,再取 1 1 1 行数放在第 2 2 2 行有 2 2 2 种方法,最后 1 1 1 行数放在第 3 3 3 行只有 1 1 1 种方法,由乘法原理得 3 × 2 × 1 = 6 3×2×1=6 3×2×1=6 种方法。更进一步,记 A n m A^m_n Anm 表示从 n n n 个不同的元素中任取 m ( m ≤ n ) m(m \le n) m(mn) 个元素,计算公式为 A n m = n ( n − 1 ) ( n − 2 ) A^m_n=n(n-1)(n-2) Anm=n(n1)(n2)··· ( n − m + 1 ) (n-m+1) (nm+1)。参考程序如下:

#include<bits/stdc++.h>
using namespace std;
int main()
{
	int a,b,c,n=0,ary[100];
	for(int i=159; i<=951; i++)
	{
		a=i/100;
		b=i/10%10;
		c=i%10;
		if(a+b+c==15&&a!=c&&a!=b&&b!=c&&a*b*c!=0)
			ary[n++]=i;
	}
	int a1,b1,c1,a2,b2,c2,a3,b3,c3;
	for(int i=0; i<n; i++)
		for(int j=i+1; j<n; j++)
			for(int k=j+1; k<n; k++)
			{
				a1=ary[i]/100;b1=ary[i]/10%10;c1=ary[i]%10;
				a2=ary[j]/100;b2=ary[j]/10%10;c2=ary[j]%10;
				a3=ary[k]/100;b3=ary[k]/10%10;c3=ary[k]%10;
				if(a1+a2+a3==15&&b1+b2+b3==15&&c1+c2+c3==15&&a1*b1*c1*a2*b2*c2*a3*b3*c3==362880)
				{
					if(a1+b2+c3==15&&c1+b2+a3==15)
						printf("%d\n%d\n%d\n\n",ary[i],ary[j],ary[k]);
					if(a1+b3+c2==15&&c1+b3+a1==15)
						printf("%d\n%d\n%d\n\n",ary[i],ary[k],ary[j]);
					if(a2+b1+c3==15&&c2+b1+a3==15)
						printf("%d\n%d\n%d\n\n",ary[j],ary[i],ary[k]);
					if(a2+b3+c1==15&&c1+b3+a2==15)
						printf("%d\n%d\n%d\n\n",ary[j],ary[k],ary[i]);
					if(a3+b2+c1==15&&c3+b2+a1==15)
						printf("%d\n%d\n%d\n\n",ary[k],ary[j],ary[i]);
					if(a3+b1+c2==15&&c3+b1+a2==15)
						printf("%d\n%d\n%d\n\n",ary[k],ary[i],ary[j]);
				}
			}
	return 0;
}

当然,我们还可以继续深入。仔细推算可以发现,根据其奇偶性质,满足条件的只有下面的这一种情况:

如图所示
而偶数仅有 2 2 2 4 4 4 6 6 6 8 8 8 4 4 4 个数,正好占据了矩阵的 4 4 4 个角。那么到了这里,我们就完全可以根据现有的矩阵填充的数学规律,直接填写出满足条件的一个答案,如下图所示:

如图所示
上图的填充规律是,在第 1 1 1 行中间填 1 1 1 ,然后 1 1 1 的右上角即 2 2 2 的位置(行越界则移到最后一行), 2 2 2 的右上角即 3 3 3 的位置(列越界则移到第 1 1 1 列)以此类推。一直到碰到已经填好的数为止,此时数向下填。填好后将此序列进行旋转 90 90 90 度和上下翻转即可。

Code

#include<bits/stdc++.h>
using namespace std;
int a[3][3],b[3][3];
int main()
{
	int x=0,y=1;
	a[0][1]=1;
	for(int i=2; i<=9; i++)
	{
		int tx=(x+2)%3;
		int ty=(y+1)%3;
		if(a[tx][ty]==0)
		{
			a[tx][ty]=i;
			x=tx;
			y=ty;
		}
		else
		{
			x=(x+1)%3;
			a[x][y]=i;
		}
	}
	for(int i=0; i<=3; i++)
	{
		printf("%d%d%d\n",a[0][0],a[0][1],a[0][2]);
		printf("%d%d%d\n",a[1][0],a[1][1],a[1][2]);
		printf("%d%d%d\n\n",a[2][0],a[2][1],a[2][2]);
		printf("%d%d%d\n",a[2][0],a[2][1],a[2][2]);
		printf("%d%d%d\n",a[1][0],a[1][1],a[1][2]);
		printf("%d%d%d\n\n",a[0][0],a[0][1],a[0][2]);
		for(int ii=0; ii<3; ii++)
			for(int jj=0; jj<3; jj++)
				b[jj][2-ii]=a[ii][jj];
		for(int ii=0; ii<3; ii++)
			for(int jj=0; jj<3; jj++)
				a[ii][jj]=b[ii][jj];
	}
	return 0;
}

感谢大家的阅读,有不足之处请广大网友在下方评论区指出。戳这里看上一篇文章。拜拜!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值