第1步首先计算每行数字之和。
1-9九个数字之和:1+2+3+4+5+6+7+8+9=45
九宫格共有三行,并且每行的数字之和相等,因此45/3=15,即每行数字之和为15。
第2步计算中间格的数字。
考虑第2行,第2列,和2条对角线的数字之和。它们的总和为 15/4 = 60。在它们的总和中,中间格子的数字出现了4次,其它位置格子的数字都出现了而且仅出现了1次。
所以,它们的总和=(4×中间格子的数字)+(其它8个数字)
=(3×中间格子的数字)+(1-9九个数字之和)
因此, 60=3×中间格子的数字+45,中间格子的数字等于5
第3步,奇数不能出现在4个角上的格子里。
比如,如果数字9出现在角上的格子里,那么为了保证9所在行或所在列的数字和为15,必须需要4个数字,两两之和必须为6。1,2,3,4,6,7,8中,只有2和4组成和为6的数字对,找到第2个和为6的数字对是不可能的。因此,数字9不能出现在4个角上的格子里。
同样道理,1,3,7也不能出现在4个角上的格子里。
第4步,2,4,6,8必须填在4个角上的格子里,并且保证对角线数字和为15。
第5步,将1,3,7,9填入相应的格子里就完成了九宫格填数字任务,注意和为15的条件。
完成了填九宫格的任务后,我们进一步考虑,如果上面九宫格内所有数字都加数字1会发生什么呢?即可不可以用数字2,3,4,5,6,7,8,9,10填九宫格,得到每一行,每一列,每一对角线的三个数字之和都相等的新九宫格呢。
显而易见,上面九宫格每行每列每对角线数字之和为18,奇数3,5,7,9处在4个角上的格子里,中间数6处在中间的格子里。
从1-9和2-10各九个数字所填充的九宫格可以得出下列规律:
1)九个数字是由9个相连的整数构成的。
2)九个数字中正中间的数字填在九宫格的中间格子里。1-9中的5,2-10中的6等。
3)每行每列的数字和等于中间数字的三倍。比如15=5´3和18=6´3。
4)第2,4,6,8位的数字填充到4个角上的格子里。如2,3,4,5,6,7,8,9,10中的3,5,7,9和1,2,3,4,5,6,7,8,9中的2,4,6,8。
问题1:已知9个相连的整数填充的九宫格其每行数字和为45,求这九个数字。
中间格数字为45¸3=15,15为正中间的数字,因此九个数字为11,12,13,14,15,16,17,18,19。
问题2:已知9个相连的整数填充的九宫格其每行数字和为96,求九宫格4个角上格子里的数。
96¸3=32,得到九个数字为28,29,30,31,32,33,34,35,36。4个角上的数字为29,31,33,35,其中35和29为对角关系,31和33为对角关系。
问题3:成公差为d(d!=0)的等差数列是否也填九宫格?比如公差为3的等差数列,1,4,7,10,13,16,19,22,25,如何填九宫格呢?5,15,25,35,45,55,65,75,85又怎样填?
古人说,“学贵有疑。小疑则小进,大疑则大进”。在学习中,我们要注意归纳和演绎能力的培养,总结一些规律,不但增加了学习的有效性和趣味性,对理解和掌握有关问题也很有益处。培育创新型人才既是学校和老师的责任,也是我们学生要刻意磨练的目标。本文通过详解九宫格问题,得到了一些有意义的结论和规律,而这些规律的获得使我们对九宫格问题也有了更加深入的认识。
幻方的求解
三阶幻方的解法
第一种:杨辉法:九子斜排,上下对易,左右相更,四维挺出。
1
2 4
3 5 7
6 8
9
2 9 4
7 5 3
6 1 8
第二种:九宫图也是幻方的别称,三阶幻方就是著名的洛书,他的排列是::“戴九履一,左三右七,二四为肩,六八为足,五居(9在上中,1在下中。3在左中,7在右中,2在左上,4在右上,6在左下,8在右下)
第三种:罗伯法:最小的数据上行,依次向右上方斜填,上出框往下写,右出框往左填,排重便在下格填,右上排重一个样
8 1 6
3 5 7
4 9 2
四阶幻方的解法
1、先把这16个数字按顺序从小到到排成一个4乘4的方阵
2、内外四个角对角上互补的数相易,(方阵分为两个正方形,外大内小,然后把大正方形的四个对角上的数字对换,小正方形四个对角上的数字对换)即
(1,16)(4,13)互换
(6,11)(7,10)互换
16 2 3 13
5 11 10 8
9 7 6 12
4 14 15 1
另:对于n=4k阶幻方,我们先把数字按顺序填写。写好后,按4*4把它划分成k*k个方阵。因为n是4的倍数,一定能用4*4的小方阵分割。然后把每个小方阵的对角线,象制作4阶幻方的方法一样,对角线上的数字换成互补的数字,就构成幻方。
五阶幻方的解法:罗伯法:最小的数据上行,依次向右上方斜填,上出框往下写,右出框往左填,排重便在下格填,右上排重一个样。
17 24 1 8 15
23 5 7 14 16
4 6 13 20 22
10 12 19 21 3
11 18 25 2 9
(在最上一行的中间填1,接着在1的右上方填2,由于1在最上一行,
所以1的右上方应该是第五行的第四个,
接下来在2的右上方填3,3的右上方应该是第三行第一个,所以在此填4,在4的右上方填5,
在5的下方填6,接着按前面五个数的填法依次填7,8,9,10;
在10的下方填11,然后按上面的方法填,
每次填五个数,直到完成.
无论从上到下还是从左到右都是五排,
所以每排的五个数之和为(1+2+3+4+…+25)÷5=65,
因此,你可以验算一下是否每个和都是65.
此法适合于一切奇阶幻方.)
数独游戏
数独,据说最先是在瑞典,后来到美国,然后到日本被发扬光大。这个游戏,进入了今年上海交大的自主招生试题——最后一道大题就是数独题。
上面的图片中,红色是在玩游戏前给出的数字,蓝色的数字就是后填的。
游戏的规则很简单,每一行填入1—9九个数字,每一列也填入1—9九个数字,但同时要满足每一个九宫格中也包含1—9九个数字,也就是说每一个九宫格中也填入1—9九个数字。
此图的特别之处就是横行纵列加上两条对角线上的三个数字之和均为15。
类似于这样的问题,也称之为幻方,像上面的九宫格,可称为3阶幻方(因每行,每列,两条对角线上数字个数是3),还有4阶、5阶、6阶等。此外还可分为奇阶幻方和偶阶幻方。九宫格就属于奇阶幻方。
下面是个五阶幻方。
幻方的填写是有规律的,我想通过上面两个两个幻方可以找到一些规律。偶阶幻方的填写规律比奇阶幻方要稍微复杂——小声点说,我还不是太明白,还在继续学习中。
练习1:.完成一道数独游戏题吧,说不定下回哪个考试也会有这样的题呢!
练习2:3阶幻方三个数的和是15,5阶幻方五个数的和是65,你能说出7阶幻方中七个数的和 是多少吗?进一步,你能说出奇阶幻方中n个数字的和是多少吗?
练习3: 完成一个7阶幻方。
比如说三阶幻方,先向外翻折扩展,然后按上图左二的规律,按顺序写上1-9的数字,接下来幻方之外的数,按左往右仍,右往左仍,上往下扔,下往上扔的规律填进幻方,将其余的删去,就得到一个横竖斜都等于15的幻方了!
下图是五阶幻方的解法,方法相同,只是规模大了点。
七阶幻方如下:(唉,上面那种做图太累,后面的图就来自于互联网了。)
只要按照这个方法,无论多少阶,只要是个奇数,都可以画得出来,至少一个!你可以奸诈一点,比如说画好菱形后,1的起始位置是可以换的,写的方向也是可以换的,但是最后出来的幻方本质上是一样的。
对于偶数呢,最小是4阶的,四阶的幻方老师也讲了一个解法,就是大对角线换,小对角线也换。步骤如下:
先按顺序写出1-16的数在4阶幻方里面,如下:
接下来所谓的大对角线换,小对角线换就是1和16换,4和13换,6和11,7和10,换完就出来了:
横竖斜都是34。
然后问题就来了,有没有办法可以解出任意高偶数阶的幻方的方法呢?
我曾经很傻很天真的试图把4阶这种换对角线的方法推广到6阶,但是怎么弄都未果,估计这种方法对于4阶只是种巧合吧。
后来大学玩matlab后,发现matlab里面函数magic可以输出任意阶的幻方,哦,soga,原来真的有的啊。
后来我就对着matlab里面magic的源文件写出了这个C++版本,只是为了巩固自己对四阶的理解罢了。
然后下面整理一下一般的偶数阶幻方的解法,解法来源于互联网。
首先一般的偶数阶解法都是把偶数分成两种,4,8,12,16这种4m的双偶数和6,10,14这种4m+2的单偶数,一般的解法都是分开来两类的,包括matlab里面的magic函数,不过查了一下也有很多大牛研究出了统一解法,更有大神把奇偶阶全部同意了,膜拜ing。。
双偶数解法:偶数阶下面先讲简单的双偶数解法,看了很多解法,但是最后发现了一个通解,网上看到的大部分解法都是这个通解的特例。
首先呢,如下图所示,先把n阶幻方分成4个小块,对于左上角那个你任意的把一半放个填成灰色,但是有一个约束条件,就是左上角这个小块中每一行每一列都要只有n/4个灰色的。然后呢,右上的那个小块的填色方案就是左上填色方案的左右镜像对称,左下的就是左上天色方案的上下镜像对称,自然,右下就是左上的中心对称了。如下图所示:
然后呢,你把1-n²这么多个数按顺序填进白色的格子里去,灰色的部分要留着。如下面左图所示:
之后呢,把剩下的没填的数反过来填进去,也就是从右下到左上的顺序,填完双偶数阶幻方就出来了。
现在我们来讨论一下这种方法,首先看我们原本的四阶幻方的解法,有没有发现其实和这种方法是一个东西。
然后再看看双偶数阶的另一种解法,比如说下面这个8阶幻方:
这里的解法呢,就是把整个幻方分成2×2个4×4的小块,按顺序填好1-个数,然后每个4×4小块的对角线上的数不变,其余的数做中心对称。
再看看下面这个:
12阶,分成3×3个4×4的小块,和之前一样,按顺序填好数,然后每个4×4小块的对角线上的数不变,其余的数做中心对称。
虽然和我最开始的那种分法不一样,但是你仔细一想,其实是完全一样的,只是他的填色方案是固定的一种模式而已。
还有一种说法是每个小块对角线上的数换成互补的那个数,其实本质还是一样嘛。
下面是一个双偶数的matlab程序,我填色方案用时是国际象棋棋盘那种黑白相间。
function a = hf_4m(n)
flag = zeros(n/2,n/2);
flag(1:2:n/2,1:2:n/2) = 1;
flag(2:2:n/2,2:2:n/2) = 1;
flag = [flag fliplr(flag);flipud(flag) flipud(fliplr(flag))];
a = reshape(1:n^2,n,n)';
a = a .* flag;
a = reshape(a',1,n^2);
blank_idx = find(a==0);
number_left = (1:n^2) .* (a==0);
number_left = fliplr(setdiff(number_left,0));
a(blank_idx) = number_left;
a = reshape(a,n,n)';
单偶数解法:下面来看看单偶数的解法,这种现在主要有两种方法,分区法和易位法。其中呢,分区法也有两种。
先说分区法,首先呢就是把方阵划分成下面A,B,C,D四块,因为是单偶数,所以每一块必然是个奇数幻方。
然后把1~n²/4这些数组成的奇数阶幻方算出来,填进A里面,然后接下来的n²/4的幻方填进D里面,(其实有个很简单的方法,就是把A里面的每个数加上n²/4就可以了),再把D里面的加上n²/4放到B里面,最后那些放到C里面。下面是10阶幻方的一个例子:
然后下面的东西有点拗口,但是细细读就会明白了:
先假设阶数是4k+2,那么k=(n-2)/4,然后下面是第一种方法:
从A小块的中间行中间格开始(上图中的13),向右找k个数(包括中间行中间格那个),和C小块的相应位置的数换位。A小块的其他行(也就是除了最中间那一行)从最左开始数出k个数,和C中相应位置的数换。
B小块中间列开始,向左数K-1列出来(当然也包括B小块中间那一列),然后这些列和D小块中相应未知的数换位。(6阶k-1=0,就不用了)
然后就完成了。
14阶幻方的换位方式如下:
这种方法的matlab函数如下:
function a = hf_4m_2(n)
a = zeros(n,n);
a(1:n/2,1:n/2) = magic(n/2);
a(n/2+1:n,n/2+1:n) = a(1:n/2,1:n/2) + n^2/4;
a(1:n/2,n/2+1:n) = a(1:n/2,1:n/2) + n^2/4*2;
a(n/2+1:n,1:n/2) = a(1:n/2,1:n/2) + n^2/4*3;
m = (n/2-1)/2;
temp = a((n/2+1)/2,(n/2+1)/2:(n/2+1)/2+m-1);
a((n/2+1)/2,(n/2+1)/2:(n/2+1)/2+m-1) = a((n/2+1)/2+n/2,(n/2+1)/2:(n/2+1)/2+m-1);
a((n/2+1)/2+n/2,(n/2+1)/2:(n/2+1)/2+m-1) = temp;
temp = a(setdiff(1:n/2,(n/2+1)/2),1:1+m-1);
a(setdiff(1:n/2,(n/2+1)/2),1:1+m-1) = a(setdiff(1:n/2,(n/2+1)/2)+n/2,1:1+m-1);
a(setdiff(1:n/2,(n/2+1)/2)+n/2,1:1+m-1) = temp;
if(m>1)
temp = a(1:n/2,n*3/4+1/2-m+2:n*3/4+1/2);
a(1:n/2,n*3/4+1/2-m+2:n*3/4+1/2) = a(1+n/2:n,n*3/4+1/2-m+2:n*3/4+1/2);
a(1+n/2:n,n*3/4+1/2-m+2:n*3/4+1/2) = temp;
end
然后还有一种换位方法,A小块中间那一行第2列开始往右数k个数,和C小块中相应位置的数换位,A小块中其余行都从最左开始向右数k列,这些数也和C小块的做交换。B小块中,从最右开始向左数k-1个列,与D中相应位置的数换位,结果也是一样的。这种方法matlab代码如下:
function a = hf_4m_2(n)
a = zeros(n,n);
a(1:n/2,1:n/2) = magic(n/2);
a(n/2+1:n,n/2+1:n) = a(1:n/2,1:n/2) + n^2/4;
a(1:n/2,n/2+1:n) = a(1:n/2,1:n/2) + n^2/4*2;
a(n/2+1:n,1:n/2) = a(1:n/2,1:n/2) + n^2/4*3;
m = (n/2-1)/2;
temp = a((n/2+1)/2,2:2+m-1);
a((n/2+1)/2,2:2+m-1) = a((n/2+1)/2+n/2,2:2+m-1);
a((n/2+1)/2+n/2,2:2+m-1) = temp;
temp = a(setdiff(1:n/2,(n/2+1)/2),1:1+m-1);
a(setdiff(1:n/2,(n/2+1)/2),1:1+m-1) = a(setdiff(1:n/2,(n/2+1)/2)+n/2,1:1+m-1);
a(setdiff(1:n/2,(n/2+1)/2)+n/2,1:1+m-1) = temp;
if(m>1)
temp = a(1:n/2,n:-1:n-m+2);
a(1:n/2,n:-1:n-m+2) = a((1:n/2)+n/2,n:-1:n-m+2);
a((1:n/2)+n/2,n:-1:n-m+2) = temp;
end
这两中方法为什么可行我还没仔细研究,但是刚刚编程发现一个很神奇的现象,就是第一种方法的BD小块交换规则配上第二种方法的AC小块交换规则,也是可以的。囧。
对于单偶数的幻方,还有一种杨辉创造的二阶方阵易位法(我发现杨辉老兄很喜欢玩数阵)。
对于n = 4m+2阶幻方,先用奇数阶的方法做出一个2m+1阶幻方来,然后把1~n²那么多个数4个一组,分成(2m+1)²个组,{1,2,3,4}{5,6,7,8}{9,10,11,12}…分别称为第1组,第2组,第3组…第(2m+1)²组。
接下来那每一组四个数按下面的方法放入2×2的方阵中:
然后把之前那个2m+1阶幻方,每个位置上的数如果是i,那么就换成第i组2×2方阵,这样就有了一个n×n的方阵了,但是这个方阵还不是幻方,需要再修正。
我们继续讨论刚才那一个2m+1阶幻方,假设我们n=14,那么2m+1 = 7,对于下图中这个7阶的方阵,我们把倒数第二行染绿,然后从中间那一行开始向下知道倒数第三行为止全部染蓝,如果中间那一行就是倒数第二行,那么不染蓝。
接下来在把最左和最右两列的染色向下拉一格。如下图:
我们知道对应于刚刚做出来的那个n×n的方阵,每2×2方阵,四个数对应于上图的一个格。我们现在做如下操作,如果是绿色的格子,那么2×2方阵的最下面两个数交换,如果是蓝色格子的话,2×2方阵不仅下面两个数交换,而且上面两个数也要交换。
下面举个例子:
对于14阶幻方,先生成一个7阶幻方
然后把相应位置填上相应的2阶方阵:
填好色:
绿色格子下面两个数换位,蓝色的上下都换,就得到结果啦~~~
杨辉易位法代码如下:
function a = hf_4m_2_yiwei(n)
h = magic(n/2);
a = zeros(n,n);
for i = 1 : n/2
for j = 1 : n/2
a(i*2-1:i*2,j*2-1:j*2) = [2 3;4 1] + (h(i,j)-1)*4;
end
end
flag = zeros(n/2,n/2);
flag(n/2-1,:) = 1; %%下面两个互换
if(n > 6)
flag((n/2+1)/2:n/2-2,:) = 2;%%上面下面都要换
end
flag(2:n/2,[1 n/2]) = flag(1:n/2-1,[1 n/2]);
for i = 1 : n/2
for j = 1 : n/2
if(flag(i,j) >0)
temp = a(i*2,j*2-1);
a(i*2,j*2-1) = a(i*2,j*2);
a(i*2,j*2) = temp;
end
if(flag(i,j) == 2)
temp = a(i*2-1,j*2-1);
a(i*2-1,j*2-1) = a(i*2-1,j*2);
a(i*2-1,j*2) = temp;
end
end
end
哟西,好了,终于写的差不多了。自个研究了一下,收获颇多。不过幻方可不仅仅是构造那么简单,以前看的一本书里面有各种变态的幻方,什么切尾幻方什么的。还有很多数学上的东西,下面提问,请证明:偶数阶幻方行列式值一定是0!
下面附上一个很多年前改写matlab的magic函数的C++代码:
#include #include classmagic { public: int **m; magic(); magic(int n); magic(magic &c); void show(); int size; }; magic::magic(magic &c) { int n=c.size; size=n; m=newint*[n]; for(int l=0;l m[l]=newint[n]; for(int k=0;k m[l][k]=c.m[l][k]; } } } magic::magic(int n) { size=n; m=newint*[n]; for(int l=0;l m[l]=newint[n]; for(int k=0;k } } void magic::show() { for(int l=0;l for(int k=0;k cout< magiccreatmagic(int n) { intl,k; if(n%2==1) { magic i(n),j(n),m(n),a(n),b(n); for(l=0;l j.m[l][k]=k+1; i.m[l][k]=l+1; } for(l=0;l a.m[l][k]=(i.m[l][k]+j.m[l][k]-(n+3)/2)%n; if(a.m[l][k]<0) a.m[l][k]+=n; b.m[l][k]=(i.m[l][k]+j.m[l][k]*2-2)%n; if(b.m[l][k]<0) b.m[l][k]+=n; m.m[l][k]=n*a.m[l][k]+b.m[l][k]+1; } return m; } elseif(n%4==0) { magic i(n),j(n),d(n),m(n); for(l=0;l j.m[l][k]=k+1; i.m[l][k]=l+1; d.m[l][k]=( ((i.m[l][k]%4)/2) == ((j.m[l][k]%4)/2) ); m.m[l][k]=l*n+k+1; if(d.m[l][k]==1) m.m[l][k]=n*n+1-m.m[l][k]; } return m; } else { int p=n/2; magic t(creatmagic(p)),m(n); for(l=0;l elseif(l m.m[l][k]=t.m[l][k-n/2]+2*p*p; elseif(l>=n/2&&k else m.m[l][k]=t.m[l-n/2][k-n/2]+p*p; } int e=(n-2)/4; //cout< if( ( l>=0 && l<=(e-1) ) || ( l>=(n+1-e) )) { for(k=0;k int temp=m.m[k][l]; m.m[k][l]=m.m[k+n/2][l]; m.m[k+n/2][l]=temp; } } } int temp=m.m[e][0]; m.m[e][0]=m.m[e+n/2][0]; m.m[e+n/2][0]=temp; temp=m.m[e][e]; m.m[e][e]=m.m[e+n/2][e]; m.m[e+n/2][e]=temp; return m; } } void main() { float m; int n; while(1) { cout<<"input the size:"; cin>>m; n=int(m); if(n==2||n<=0) continue; magic result(creatmagic(n)); result.show(); cout<<"每一列和为:\\n"; for(int l=0;l cout< for(int k=0;k sum+=result.m[l][k]; cout< cout<<"+"; } cout<<"="< cout<<"每一行和为:\\n"; for( l=0;l int sum=0; cout< sum+=result.m[k][l]; cout< cout<<"+";} cout<<"="< int sum=0; cout<<"主对角线和为:"; for( l=0;l sum+=result.m[l][l]; if(l==n-1) cout< cout< cout<<"="< cout<<"次对角线和为:"; for( l=0;l sum+=result.m[l][n-1-l]; if(l==n-1) cout< cout<<"="< }