这可以通过线程运行得更快吗?

时间:2013-08-16 23:15:48

标签: vb.net multithreading

我目前正在编写一个解决脑筋急转弯的程序, screen

这是如何工作的: 仅使用数字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

3 个答案:

答案 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想出了这个数学。

  • 所有可能数字的总和(1-9)= 45
  • diag1val(26)+ diag2val(26) - sum = center square value - 52-45 = 7
  • sum - cornervals - centerval = 4个raidal盒子的值 - &gt; 45 - 26 - 7 = 12
  • 12只能是1,2,3,6或1,2,4,5
  • 的某些组合

答案 2 :(得分:0)

如果你有一个简单的“尝试所有可能性”方法,那么对代码进行并列化肯定会使它更快。这很简单,因为线程之间不需要共享更改数据。