问题:
在一个3*3的方格内填入9个数字,数字的范围从1~9,每个数字仅出现一次,使得每行、每列以及两个对角线的数字之和为15。
一、VBA程序
算法思路:
1、将9个数字分成3组,每组3个数字,使得每组数字之和为15。
2、将第二个数字为5个分组单独选出,作为方格的第二行数组。
3、循环抽取其它的分组,与第二分组进行重复性判断。
4、如果没有重复,记录这3种分组。
5、将这3种分组传人判断函数,核实是否满足条件。
6、如果满足条件,将结果输出。
VBA源程序如下:
运行结果
6 7 2
Sub jiugongsuan_All()Dim cs(1 To 9) As Integer
Dim jgs1(1 To 3) As Integer
Dim Ot() As Integer
'第一、三行数组
Dim Sec() As Integer
'第二行数组
Dim temp1(1 To 100, 1 To 3) As Integer
Dim temp2(1 To 100, 1 To 3) As Integer
'temp1、temp2分别为临时数组
Dim Totali As Integer
'第二个数为5,三个数之和为15的数组个数
Dim Totaln As Integer
'不包括第二个数为5,三个数之和为15的数组个数
Dim at(1 To 3) As Integer
Dim bt(1 To 3) As Integer
Dim ct(1 To 3) As Integer
'at、bt、ct分别为中间变量数组Dim scjg(1 To 3, 1 To 3) As Integer
'scjg为结果数组Dim i As IntegerTotali = 0
Totaln = 0For i = 1 To 9
'初始数组赋值
cs(i) = iNextFor m = 1 To 9If cs(m) <> 0 Then
' 判断该数字是否已被占用jgs1(1) = cs(m)cs(m) = 0
' 占用该数字For n = 1 To 9If cs(n) <> 0 Thenjgs1(2) = cs(n)cs(n) = 0For q = 1 To 9If cs(q) <> 0 Thenjgs1(3) = cs(q)cs(q) = 0If jgs1(1) + jgs1(2) + jgs1(3) = 15 Then' Debug.Print jgs1(1); jgs1(2); jgs1(3)If jgs1(2) = 5 Then'第二行数据Totali = Totali + 1temp1(Totali, 1) = jgs1(1)temp1(Totali, 2) = jgs1(2)temp1(Totali, 3) = jgs1(3)Else
' 第一行,第三行数据Totaln = Totaln + 1temp2(Totaln, 1) = jgs1(1)temp2(Totaln, 2) = jgs1(2)temp2(Totaln, 3) = jgs1(3)End IfEnd Ifcs(q) = qEnd IfNextcs(n) = nEnd IfNextcs(m) = mEnd IfNextReDim Sec(1 To Totali, 1 To 3)
ReDim Ot(1 To Totaln, 1 To 3)For m1 = 1 To Totali
Sec(m1, 1) = temp1(m1, 1)
Sec(m1, 2) = temp1(m1, 2)
Sec(m1, 3) = temp1(m1, 3)'第二行数组赋值NextFor n1 = 1 To Totaln
Ot(n1, 1) = temp2(n1, 1)
Ot(n1, 2) = temp2(n1, 2)
Ot(n1, 3) = temp2(n1, 3)Next'第一、三行数组赋值For m1 = 1 To Totalibt(1) = Sec(m1, 1)bt(2) = Sec(m1, 2)bt(3) = Sec(m1, 3)For n1 = 1 To Totalnat(1) = Ot(n1, 1)at(2) = Ot(n1, 2)at(3) = Ot(n1, 3)If cfpd(at, bt) ThenElseFor k1 = 1 To Totalnct(1) = Ot(k1, 1)ct(2) = Ot(k1, 2)ct(3) = Ot(k1, 3)If Not cfpd(at, ct) And Not cfpd(bt, ct) Then
' 第一、三行,第二、三行重复情况判断scjg(1, 1) = at(1)scjg(1, 2) = at(2)scjg(1, 3) = at(3)scjg(2, 1) = bt(1)scjg(2, 2) = bt(2)scjg(2, 3) = bt(3)scjg(3, 1) = ct(1)scjg(3, 2) = ct(2)scjg(3, 3) = ct(3)' 调用函数finalpd (scjg)ElseEnd IfNextEnd IfNextNextEnd SubFunction cfpd(a() As Integer, b() As Integer) As Boolean
'2个数组重复情况判断If b(1) <> a(1) And b(1) <> a(2) And b(1) <> a(3) Thencfpd = FalseElsecfpd = TrueExit FunctionEnd IfIf b(2) <> a(1) And b(2) <> a(2) And b(2) <> a(3) Thencfpd = FalseElsecfpd = TrueExit FunctionEnd IfIf b(3) <> a(1) And b(3) <> a(2) And b(3) <> a(3) Thencfpd = False
Elsecfpd = TrueExit FunctionEnd IfEnd FunctionSub finalpd(sz As Variant)
'列求和、对角线求和判断Dim i%, j%
Dim myjgs(1 To 3, 1 To 3)
Dim Hpd As Boolean
Dim Lpd As Boolean
Dim DJXpd As BooleanFor i = 1 To 3For j = 1 To 3myjgs(i, j) = sz(i, j)Next
Next'列判断
For i = 1 To 3If myjgs(1, i) + myjgs(2, i) + myjgs(3, i) = 15 Then
Lpd = True
Else
Lpd = False
Exit For
End IfNext'对角线判断If myjgs(1, 1) + myjgs(2, 2) + myjgs(3, 3) = 15 And myjgs(1, 3) + myjgs(2, 2) + myjgs(3, 1) = 15 ThenDJXpd = TrueElseDJXpd = False
End IfIf Lpd And DJXpd Then'结果输出Debug.Print myjgs(1, 1); myjgs(1, 2); myjgs(1, 3)Debug.Print myjgs(2, 1); myjgs(2, 2); myjgs(2, 3)Debug.Print myjgs(3, 1); myjgs(3, 2); myjgs(3, 3)Debug.Print "-------------------------"End IfEnd Sub
运行结果:
6 7 2
1 5 9
8 3 4
————————-
8 3 4
1 5 9
6 7 2
————————-
4 9 2
3 5 7
8 1 6
————————-
8 1 6
3 5 7
4 9 2
————————-
2 9 4
7 5 3
6 1 8
————————-
6 1 8
7 5 3
2 9 4
————————-
2 7 6
9 5 1
4 3 8
————————-
4 3 8
9 5 1
2 7 6
二、EXCEL规划求解
1、选择数据菜单-à“规划求解”
2、设置可变单元格及约束条件
约束条件
Ø 行之和为15
Ø 列之和为15
Ø 所有数字均为整数
Ø 所有数字>=1
Ø 所有数字<=9
Ø 所有数字连乘的积为9的阶乘,这种方式可以限制每个数字出现1次,且仅出现1次。
图一
图二
这种方法只能求出一个解。