我目前正在编写一个解决脑筋急转弯的程序,
这是如何工作的: 仅使用数字1-9,使四个角,每个对角线= 26 提示中间7
无论如何,我的代码基本上从“111111111”开始并计数,每次检查它是否与所需参数匹配。
代码:
Public Class Main
Dim count As Integer
Dim split() As Char
Dim done As Boolean
Dim attempts As Integer
Private Sub IncreaseOne()
If count < 999999999 Then
count += 1
Else
done = True
End If
If CStr(count).Contains("0") Then
count = CStr(count).Replace("0", "1")
End If
End Sub
Private Sub Reset()
count = 111111111
attempts = 0
End Sub
Private Sub IntToLbl()
split = CStr(count).ToCharArray
lbl1.Text = split(0)
lbl2.Text = split(1)
lbl3.Text = split(2)
lbl4.Text = split(3)
lbl5.Text = split(4)
lbl6.Text = split(5)
lbl7.Text = split(6)
lbl8.Text = split(7)
lbl9.Text = split(8)
lblAttempts.Text = "Attempt: " & attempts
End Sub
Private Sub Check()
attempts += 1
If split(0) + split(1) + split(7) + Int(8) = 26 And split(0) + split(2) + split(4) + split(6) + split(8) = 26 And split(1) + split(3) + split(4) + split(5) + split(7) = 26 Then
If CStr(count).Contains("1") And CStr(count).Contains("2") And CStr(count).Contains("3") And CStr(count).Contains("4") _
And CStr(count).Contains("5") And CStr(count).Contains("6") And CStr(count).Contains("7") And CStr(count).Contains("8") _
And CStr(count).Contains("9") Then
ListBox1.Items.Add("A" & attempts & ": " & CStr(count))
End If
End If
End Sub
Private Sub Act()
While done = False
IncreaseOne()
IntToLbl()
Check()
End While
tr.Abort()
End Sub
Dim suspended As Boolean = False
Dim tr As New System.Threading.Thread(AddressOf Act)
Private Sub Button1_Click(sender As Object, e As EventArgs) Handles btnSolve.Click
If suspended = True Then
tr.Resume()
suspended = False
Else
If tr.IsAlive = False Then
Reset()
tr.Start()
CheckForIllegalCrossThreadCalls = False
Else
Dim Reply = MsgBox("Thread is running! Stop the thread?", MsgBoxStyle.YesNo, "Error!")
If Reply = MsgBoxResult.Yes Then
tr.Suspend()
suspended = True
End If
End If
End If
End Sub
Private Sub Main_FormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
tr.Abort()
End Sub
Private Sub tr2_Tick(sender As Object, e As EventArgs) Handles tr2.Tick
IncreaseOne()
IntToLbl()
Check()
End Sub
End Class
答案 0 :(得分:4)
在使用线程之前,您应该1)降低算法复杂度,2)提高效率。
1)对于复杂性,由于数字只能在这里一次,你有9个! = 362.880测试要做,这比完全扫描的测试少27.557倍 我想那时候你已经在大多数计算机上都是实时的,但也可能有一些组合你可以在测试所有子组合之前停止测试(探索:如果第一个对角线不是26,不需要测试其他项目的排列)。有了这个,你可以减少更多的测试。 减少案件数量的另一种方法是使用对称性。这里,1步或2步旋转,水平或垂直翻转不会影响结果,这使得另一个X16切入测试计数。
2)为了提高效率,使用整数数组而不是字符串将为您带来巨大的速度提升。
我做了一个jsfiddle(在javascript中,所以),这只是测试9!元素和使用数组,它立即给出结果,所以我没有进一步寻找早期停止/对称。
一种解决方案是,例如:3,2,7,5,9,6,1,4,8
这使得:
3 6
2 1
7
4 5
8 9
似乎没问题。
小提琴在这里:http://jsfiddle.net/HRdyf/2/
这些数字以这种方式编码:第一个对角线有5个第一个数字, 中心项目有索引2,其他4个是第二个对角线除外 它的核心项目。 (正如所解释的那样,可能有更有效的方法对阵列进行编码 早些时候,先停止一些测试。)
Rq:我们可以找到所有带数学的解决方案:
让我们调用c1,c2,c3,c4的四个角,c中心点,d11,d12,d21,d22这两个
两个对角线的剩余点。
然后
1)c1 + c2 + c3 + c4 = 26
2)c1 + d11 + m + d12 + c3 = 26
3)c2 + d21 + m + d22 + c4 = 26
4)所有点都不同,在1..9范围内
5)(从4):所有点的总和= 45(从1到9的总和)
6)来自5)和1) - &gt; d11 + d12 + m + d21 + d22 = 45-26 = 19
(内点总数=总数 - 角落总数)
7)现在添加2)和3)并使用1)和6)我们有19 + 26 + m = 26 + 26
所以---&gt;&gt;&gt; M = 7
8)考虑到1)和4)和7),我们看到我们不能用四个整数来达到26
不同于7而不同时使用9和8,(最大值我们可以达到7和
9是8 + 6 + 5 + 4 = 25,没有7和8的最大值是9 + 6 + 5 + 4 = 24)
所以 - &gt;两个角有9,8个值
9)对于8),1),7)和4):另外两个角只能是6,3或5,4
(如果r1和r2不是9或8角,我们有r1 + r2 = 9)
此时:中心为7,角为[4,5,8,9]或[3,6,8,9](和排列)
对于[4,5,8,9] - &gt;遗骸[1,2,3,6](总和= 12)
对于[3,6,8,9] - &gt;仍然[1,2,4,5](总和= 12)
我们不能在相同的对角线上有9和8,因为8 + d11 + 7 + d12 + 9 = 26使得d11 + d12 = 2这不是 可能考虑4)
让我们考虑角= [4,5,8,9]的情况,并看到对角线的结尾从9开始。它可能是 4或5 4:9 + d11 + 7 + d12 + 4 = 26 - > d11 + d12 = 6 - > (3,1)是d11和d12的唯一解决方案 - &gt; d21和d22保持(2,6) 5 - &gt;&gt; d11 + d12 = 7 - &gt;没有解决方案,给出4)并且4和5正在使用
现在角落= [3,6,8,9]的情况下,也考虑从9开始的对角线结束。它可能以6或3结束
3:d11 + d12 = 7(5,2)唯一的解决方案(4,3和6,1不能工作,因为3和6正在使用中)
6:d11 + d12 = 10无解。 (6,4 / / 7,3 / 8,2 / 9,1都使用了一个用过的数字。)
---&GT;所以从9开始的对角线只能以4或3结束 扣除---&gt;从8开始的对角线将以5结束(当另一个以4结束时)或结束为6 (当另一个以3结束时)。
有多少解决方案?
选择9的位置有4种可能性,然后是9对角线端(4或3)的2种选择,然后是8对角线的2种选择(从楼上或楼下开始),然后为d11,d12留下4种可能性; d21,d22选择:[3,1] + [2,6]如果我们选择4作为9的结尾,[5,2] + [1,4]如果我们选择3作为9的结尾。
4 * 2 * 2 * 4可提供64种解决方案组合。
答案 1 :(得分:1)
这是在编码之前需要进行一些分析(铅笔/纸张和减法)的问题之一。由于至少一个对角线必须具有9,因此该序列(对角线)的可能性很小。该序列中的下一个数字只能是8,7或6,每个数字只有几种可能性。
9 8 6 2 1
9 8 5 3 1
9 8 4 3 2
9 7 6 3 1 remaining 2 4 5 8 = 19
9 7 5 4 1 remaining 2 3 6 8 = 19
9 7 5 3 2 remaining 1 4 6 8 = 19 *
9 6 5 4 2
(我可能错过了一些???)
一旦知道少数序列,那么剩余数字的总和加上序列中的一个数字必须等于26。
编辑:多一点铅笔/纸张作品显示那些只有7个中心序列的作品。
编辑:MSDN网站上的John Wein想出了这个数学。
答案 2 :(得分:0)
如果你有一个简单的“尝试所有可能性”方法,那么对代码进行并列化肯定会使它更快。这很简单,因为线程之间不需要共享更改数据。