ชุมชนคนรักภาษาเบสิค - Visual Basic Community

 ลืมรหัสผ่าน
 ลงทะเบียน
ค้นหา
ดู: 1435|ตอบกลับ: 0

[VB.NET] การหาชุดของความยาวด้านของสามเหลี่ยมมุมฉาก (Pythagoras) ที่เป็นจำนวนเต็มทั้งหมดที่จะเป็นไปได้

[คัดลอกลิงก์]

319

กระทู้

511

โพสต์

6496

เครดิต

ผู้ดูแลระบบ

ทองก้อน ทับทิมกรอบ

Rank: 9Rank: 9Rank: 9

เครดิต
6496



ทฤษฎีบทพีทาโกรัส คือ ทฤษฎีความสัมพันธ์ระหว่างด้านทั้งสามของสามเหลี่ยมมุมฉาก สามเหลี่ยมที่มีมุมใดมุมหนึ่งตั้งฉาก 90 องศา เป็นทฤษฎีที่คิดค้นโดยพีทาโกรัส นักคณิตศาสตร์ชาวกรีก ซึ่งกล่าวถึงทฤษฎีนี้ไว้ว่า

"ในสามเหลี่ยมมุมฉากใด ๆ พื้นที่ของสี่เหลี่ยมจัตุรัสที่มีด้านเป็นด้านตรงข้ามมุมฉาก เท่ากับผลรวมพื้นที่ของสี่เหลี่ยมจัตุรัสที่มีด้านเป็นด้านประชิดมุมฉากของสามเหลี่ยมมุมฉากนั้น"

จากทฤษฎีบทพีทาโกรัส ทำให้เราสามารถเขียนสูตรพีทาโกรัสเพื่อหาความยาวของด้านต่างๆของสามเหลี่ยมมุมฉากได้ดังนี้

a² + b² = c²

โจทย์ของเราก็คือ การหาชุดของความยาวด้านของสามเหลี่ยมมุมฉากที่เป็นจำนวนเต็มทั้งหมดที่จะเป็นไปได้

ในการทดสอบค่าความถูกต้องของสมการ Pythagoras ซึ่งเป็น a^2 + b^2 = c^2 เราจะทดสอบค่า a, b, และ c ทุกคู่ที่เป็นไปได้ ซึ่งค่า a, b, และ c จะต้องเป็นจำนวนเต็มบวก และค่า c ต้องมากกว่าค่า a และมากกว่าค่า b ด้วย ดังนั้นเราสามารถใช้ Nested Loop สามชั้นเพื่อทดสอบทุกคู่ของค่า a และ b แล้วคำนวณหาค่า c เพื่อเปรียบเทียบค่าของ a^2 + b^2 ว่าเท่ากับ c^2 หรือไม่?
ข้อสังเกต:

การใช้ Nested Loop ซ้อนกันถึง 3 ลูป โดยให้ลูป B และ ลูป C ทำการอ่านค่าเริ่มต้นจาก 1 ทำให้จำนวนรอบวงในสุดจะต้องอ่านค่าและเปรียบเทียบกันถึง 100 x 100 x 100 = 1,000,000 รอบ ซึ่งจะต้องใช้เวลามาก แต่คำตอบที่ได้จะเกิดจากการย้ายข้างของ a กับ b เช่น a = 3, b = 4 คำตอบ c = 5 พอให้ a = 4, b = 3 (การเริ่มนับจาก 1) แต่คำตอบ c = 5 เหมือนเดิม ดังนั้นเราจะใช้การลดจำนวนการนับลงไป โดยให้ลูปในมีค่าเริ่มต้นจากลูปนอกแทน ...



เมื่อกำหนดค่าเริ่มต้นใหม่โดยให้ลูปในมีค่าเริ่มต้นจากลูปนอกแทน ... เราให้ลูปในมีค่าเริ่มต้นจากค่าของลูปนอกแทน คือ b เริ่มจากค่า a ส่วน c จะเริ่มจากค่า b (b จะนับค่าต่ำกว่า a ไม่ได้ และ c จะนับค่าต่ำกว่า b ไม่ได้นั่นเอง) ...
  1.             For b As Integer = a To Val(txtMaxValue.Text)
  2.                 For c As Integer = b To Val(txtMaxValue.Text)
คัดลอกไปที่คลิปบอร์ด
จากลูป b จะวนรอบเพียง 50% ส่วนลูป c จะวนรอบเหลือไม่เกิน 20% คำตอบที่ได้ก็จะเหลือเพียง 52 รายการ แต่อีก 52 รายการที่ไม่ได้นำมาคิดคำนวณ ก็คือการสลับค่ากันระหว่างค่า a และ b นั่นเอง ...


การนำ LINQ (Language Integrated Query) มาช่วยในการแก้ปัญหาของความช้าในการวนลูปแบบ Nested Loop ... LINQ (ปกติจะอ่านว่าลิ้ง แต่บางคนก็อ่านว่าลิน หรือลินคิว ก็เอาตามที่สะดวกล่ะกันครับ) เจ้าตัวนี้จัดว่าเป็นความสามารถอันทรงพลังของ WinForm หรือ .Net Framework เลยก็ว่าได้ เพราะ LINQ คือชุดคำสั่งที่ทำงานกับกลุ่มของข้อมูล คล้ายๆกับการ Query ในฐานข้อมูลยังไงยังงั้นแหละครับทั่นผู้ชม
  1.         ' / LINQ
  2.         Dim PythagoreanTriple =
  3.             From a In Enumerable.Range(1, MaxValue)
  4.             From b In Enumerable.Range(a, MaxValue)
  5.             Let c = Math.Sqrt(a * a + b * b)
  6.             Where (c = Math.Floor(c) AndAlso c <= MaxValue)
  7.             Select New With {a, b, c}
คัดลอกไปที่คลิปบอร์ด
ตัวอย่างที่แอดมินทำการทดสอบโดยให้ค่าสูงสุดที่ 100 อาจจะมองไม่เห็นผลสักเท่าไหร่ ลองใช้สัก 1,000 หรือ 10,000 รอบดู ทุกๆท่านจะได้เห็นผลลัพธ์ของการทำงานที่แตกต่างกันมากเลยทีเดียว ...

เพิ่มเติม: นอกจากจะเอา LINQ มาแก้ปัญหาแล้ว โจทย์ข้อนี้ยังนำทางให้เราไปฝึกเขียนโค้ดเพื่อแยกการทำงานของ Thread ได้ด้วย รวมไปถึงการเรียนรู้ใช้งาน  Parallel programming in .NET ... เอาไว้แอดมินจะนำมาเสนอให้ทุกๆท่านได้รับชมกันอีกทีครับ

แอดมินนำผลลัพธ์ที่ได้ไปใส่ไว้ TextBox, ListView และ DataGridView Control เพื่อสำหรับมือใหม่ๆจะได้ฝึกเรียนรู้ในการใช้งาน Control พื้นฐานต่างๆเหล่านี้ไปด้วยครับผม ...

มาดูโค้ดฉบับเต็มกันเถอะ ...
  1. Imports System.Text

  2. Public Class frmPythagoras

  3.     '/ Start-Stop Timer
  4.     Private mTimeDouble As Double
  5.     Private sWatch As New Stopwatch()

  6.     Private Sub frmPythagoras_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
  7.         lblCount.Text = ""
  8.         lblTimer.Text = ""
  9.         lblLoop.Text = ""
  10.         txtMaxValue.MaxLength = 6
  11.         '// ฝากเป็นโจทย์ไปคิดในกรณีที่เราคิดกลับ เมื่อใช้สูตร a=2n, b=n²-1, c=n²+1
  12.     End Sub

  13.     ' / -------------------------------------------------------------------------------------------------
  14.     ' / เริ่มต้นในการประมวลผลแบบพื้นฐานด้วยการใช้ Nested Loop
  15.     ' / -------------------------------------------------------------------------------------------------
  16.     Private Sub btnNestedLoop_Click(sender As System.Object, e As System.EventArgs) Handles btnNestedLoop.Click
  17.         TextBox1.Clear()
  18.         Call InitializeListView()
  19.         Call InitializeDataGridView()
  20.         '// สร้าง String Builder สำหรับเก็บค่าไปแสดงผลใน TextBox Control (System.Text)
  21.         Dim strBuilder As New StringBuilder()
  22.         '// สร้าง ListViewItem เพื่อเก็บข้อมูล
  23.         Dim items As New List(Of ListViewItem)
  24.         '// สร้าง DataTable เพื่อเก็บข้อมูลให้กับ DataGridView
  25.         Dim DT As New DataTable
  26.         With DT.Columns
  27.             .Add("A", GetType(Integer))
  28.             .Add("B", GetType(Integer))
  29.             .Add("C", GetType(Integer))
  30.         End With
  31.         lblTimer.Text = "Timer Nested Loop : "
  32.         sWatch.Reset()
  33.         sWatch.Start()
  34.         Cursor = Cursors.WaitCursor
  35.         '// ไว้นับจำนวนลูป
  36.         Dim CountLoopA As Integer = 0 : Dim CountLoopB As Integer = 0 : Dim CountLoopC As Integer = 0
  37.         '// ใช้ Nested Loop โดยกำหนดให้ลูปในใช้ค่าเริ่มต้นจากลูปนอก
  38.         '// เพราะค่าตัวแปรของ a สลับกันกับ b ก็จะไม่มีผลอะไร เช่น a = 3, b = 4 หากกลับค่า a = 4, b = 3 ก็จะทำให้ได้ค่า c = 5 เท่ากัน
  39.         '// และจะทำให้ลดจำนวนการวนรอบของลูปลงไป
  40.         For a As Integer = 1 To Val(txtMaxValue.Text)
  41.             CountLoopA += 1
  42.             For b As Integer = a To Val(txtMaxValue.Text)
  43.                 CountLoopB += 1
  44.                 For c As Integer = b To Val(txtMaxValue.Text)
  45.                     CountLoopC += 1
  46.                     ' / --------------------------------------------------------
  47.                     ' / เงื่อนไขที่ต้องการทดสอบ คือ a^2 + b^2 = c^2
  48.                     ' / --------------------------------------------------------
  49.                     If a * a + b * b = c * c Then
  50.                         '// สำหรับ TextBox Control
  51.                         strBuilder.AppendLine("a = " & a & vbTab & "b = " & b & vbTab & "c = " & c)
  52.                         '// สำหรับ ListView Control
  53.                         Dim NewItem As New ListViewItem(a) '// กำหนดค่าให้กับคอลัมน์แรก
  54.                         NewItem.SubItems.Add(b) ' เพิ่มค่าในคอลัมน์ที่สอง
  55.                         NewItem.SubItems.Add(c) ' เพิ่มค่าในคอลัมน์ที่สาม
  56.                         items.Add(NewItem)
  57.                         '// สำหรับ DataGridView Control
  58.                         Dim row As String() = New String() {"", "", ""}
  59.                         DT.Rows.Add(a, b, c)
  60.                         '// หากใช้ Exit For ก็จะช่วยให้ลดจำนวนการวนรอบลงไปได้อีก
  61.                         'Exit For
  62.                     End If
  63.                 Next
  64.             Next
  65.         Next
  66.         '// แสดงผลลัพธ์ใน TextBox Control
  67.         TextBox1.Text = strBuilder.ToString()
  68.         '// แสดงผลลัพธ์ใน ListView Control
  69.         ListView1.Items.AddRange(items.ToArray())
  70.         '// แสดงผลลัพธ์ใน DataGridView Control
  71.         DataGridView1.DataSource = DT
  72.         lblCount.Text = "จำนวน: " & DataGridView1.RowCount & " รายการ"
  73.         DT.Dispose()
  74.         txtMaxValue.Focus()
  75.         Cursor = Cursors.Default
  76.         sWatch.Stop()
  77.         mTimeDouble = sWatch.ElapsedMilliseconds * 0.001
  78.         lblTimer.Text = lblTimer.Text & mTimeDouble.ToString & " sec."
  79.         lblLoop.Text = "a = " & Format(CountLoopA, "#,##") & vbCrLf & "b = " & Format(CountLoopB, "#,##") & vbCrLf & "c = " & Format(CountLoopC, "#,##")
  80.     End Sub

  81.     ' / -------------------------------------------------------------------------------------------------
  82.     ' / สามารถใช้ LINQ ใน VB.NET เพื่อหาชุดของความยาวด้านของสามเหลี่ยมมุมฉาก
  83.     ' / Pythagorean Triplets ที่เป็นเลขจำนวนเต็มทั้งหมดที่จะเป็นไปได้ดังนี้
  84.     ' / -------------------------------------------------------------------------------------------------
  85.     Private Sub btnLinQ_Click(sender As System.Object, e As System.EventArgs) Handles btnLinQ.Click
  86.         TextBox1.Clear()
  87.         Call InitializeListView()
  88.         Call InitializeDataGridView()
  89.         '//
  90.         Dim MaxValue As Integer = Val(txtMaxValue.Text) '// กำหนดความยาวด้านสูงสุดที่ต้องการทดสอบ
  91.         '// สร้าง String Builder สำหรับเก็บค่าไปแสดงผลใน TextBox Control (System.Text)
  92.         Dim strBuilder As New StringBuilder()
  93.         '// สร้าง ListViewItem เพื่อเก็บข้อมูล
  94.         Dim items As New List(Of ListViewItem)
  95.         '// สร้าง DataTable เพื่อเก็บข้อมูลให้กับ DataGridView
  96.         Dim DT As New DataTable
  97.         With DT.Columns
  98.             .Add("A", GetType(Integer))
  99.             .Add("B", GetType(Integer))
  100.             .Add("C", GetType(Integer))
  101.         End With
  102.         lblTimer.Text = "Timer LINQ : "
  103.         sWatch.Reset()
  104.         sWatch.Start()
  105.         Cursor = Cursors.WaitCursor
  106.         ' / -------------------------------------------------------------------------------------------------
  107.         ' / LINQ
  108.         Dim PythagoreanTriple =
  109.             From a In Enumerable.Range(1, MaxValue)
  110.             From b In Enumerable.Range(a, MaxValue)
  111.             Let c = Math.Sqrt(a * a + b * b)
  112.             Where (c = Math.Floor(c) AndAlso c <= MaxValue)
  113.             Select New With {a, b, c}
  114.         ' / -------------------------------------------------------------------------------------------------

  115.         For Each triplet In PythagoreanTriple
  116.             strBuilder.AppendLine("a = " & triplet.a & vbTab & "b = " & triplet.b & vbTab & "c = " & triplet.c)
  117.             '// สำหรับ ListView Control
  118.             Dim NewItem As New ListViewItem(triplet.a) '// กำหนดค่าให้กับคอลัมน์แรก
  119.             NewItem.SubItems.Add(triplet.b) ' เพิ่มค่าในคอลัมน์ที่สอง
  120.             NewItem.SubItems.Add(triplet.c) ' เพิ่มค่าในคอลัมน์ที่สาม
  121.             items.Add(NewItem)
  122.             '// สำหรับ DataGridView Control
  123.             Dim row As String() = New String() {"", "", ""}
  124.             DT.Rows.Add(triplet.a, triplet.b, triplet.c)
  125.         Next
  126.         '// แสดงผลลัพธ์ใน TextBox Control
  127.         TextBox1.Text = strBuilder.ToString()
  128.         '// แสดงผลลัพธ์ใน ListView Control
  129.         ListView1.Items.AddRange(items.ToArray())
  130.         '// แสดงผลลัพธ์ใน DataGridView Control
  131.         DataGridView1.DataSource = DT
  132.         lblCount.Text = "จำนวน: " & DataGridView1.RowCount & " รายการ"
  133.         DT.Dispose()
  134.         Cursor = Cursors.Default
  135.         sWatch.Stop()
  136.         mTimeDouble = sWatch.ElapsedMilliseconds * 0.001
  137.         lblTimer.Text = lblTimer.Text & mTimeDouble.ToString & " sec."
  138.         lblLoop.Text = ""
  139.     End Sub

  140.     ' / -------------------------------------------------------------------------------------------------
  141.     Private Sub txtMaxValue_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles txtMaxValue.KeyPress
  142.         '// เมื่อมีการกด Enter
  143.         If Asc(e.KeyChar) = 13 Then
  144.             If String.IsNullOrWhiteSpace(txtMaxValue.Text) AndAlso Not Char.IsControl(e.KeyChar) Then
  145.                 e.Handled = True
  146.             Else
  147.                 '// ไปประมวลผล
  148.                 Call btnNestedLoop_Click(sender, e)
  149.                 e.Handled = True
  150.             End If
  151.         ElseIf Not Char.IsDigit(e.KeyChar) AndAlso Not Char.IsControl(e.KeyChar) Then
  152.             e.Handled = True '// ไม่อนุญาตให้ป้อนค่าที่ไม่ใช่ตัวเลข
  153.         End If
  154.     End Sub

  155.     Private Sub TextBox1_KeyPress(sender As Object, e As System.Windows.Forms.KeyPressEventArgs) Handles TextBox1.KeyPress
  156.         '// ป้องกันไม่ให้กดคีย์อะไรลงไปใน TextBox Control.
  157.         e.Handled = True
  158.     End Sub

  159.     ' / -------------------------------------------------------------------------------------------------
  160.     ' / Initialized DataGridView Control.
  161.     ' / -------------------------------------------------------------------------------------------------
  162.     Private Sub InitializeDataGridView()
  163.         With DataGridView1
  164.             .RowHeadersVisible = False ' True
  165.             .AllowUserToAddRows = False
  166.             .AllowUserToDeleteRows = False
  167.             .AllowUserToResizeRows = False
  168.             .MultiSelect = True ' False
  169.             .SelectionMode = DataGridViewSelectionMode.FullRowSelect
  170.             .ReadOnly = True
  171.             '// Data rows
  172.             .Font = New Font("Tahoma", 10)
  173.             .RowTemplate.MinimumHeight = 27
  174.             .RowTemplate.Height = 27
  175.             '// Autosize Column
  176.             .AutoSizeColumnsMode = DataGridViewAutoSizeColumnsMode.Fill
  177.             '// Header
  178.             With .ColumnHeadersDefaultCellStyle
  179.                 .BackColor = Color.RoyalBlue
  180.                 .ForeColor = Color.White
  181.                 .Font = New Font(DataGridView1.Font, FontStyle.Bold)
  182.             End With
  183.         End With
  184.     End Sub

  185.     ' / -------------------------------------------------------------------------------------------------
  186.     ' / Initialized ListView Control.
  187.     ' / -------------------------------------------------------------------------------------------------
  188.     Private Sub InitializeListView()
  189.         With ListView1
  190.             .Columns.Clear() '// make sure columns collection is empty.
  191.             .Items.Clear()
  192.             .View = View.Details
  193.             .HeaderStyle = ColumnHeaderStyle.Nonclickable '// set to whatever you need.
  194.             .GridLines = True
  195.             .FullRowSelect = True
  196.             .HideSelection = False
  197.             .MultiSelect = True 'False
  198.             '// Add 3 columns
  199.             .Columns.Add("A")
  200.             .Columns.Add("B")
  201.             .Columns.Add("C")
  202.         End With
  203.         With ListView1
  204.             .Columns(0).Width = ListView1.Width \ 3 - 10
  205.             .Columns(1).Width = ListView1.Width \ 3 - 10
  206.             .Columns(2).Width = ListView1.Width \ 3 - 5
  207.         End With
  208.     End Sub

  209.     Private Sub frmPythagoras_FormClosed(sender As Object, e As System.Windows.Forms.FormClosedEventArgs) Handles Me.FormClosed
  210.         Me.Dispose()
  211.         GC.SuppressFinalize(Me)
  212.         Application.Exit()
  213.     End Sub

  214.     Private Sub btnExit_Click(sender As System.Object, e As System.EventArgs) Handles btnExit.Click
  215.         Me.Close()
  216.     End Sub

  217. End Class
คัดลอกไปที่คลิปบอร์ด

ดาวน์โหลดโค้ดต้นฉบับ VB.NET (2010) ได้ที่นี่ ...

ขออภัย! โพสต์นี้มีไฟล์แนบหรือรูปภาพที่ไม่ได้รับอนุญาตให้คุณเข้าถึง

คุณจำเป็นต้อง ลงชื่อเข้าใช้ เพื่อดาวน์โหลดหรือดูไฟล์แนบนี้ คุณยังไม่มีบัญชีใช่ไหม? ลงทะเบียน

x
สิ่งที่ดีกว่าการให้ คือการให้แบบไม่มีที่สิ้นสุด
ขออภัย! คุณไม่ได้รับสิทธิ์ในการดำเนินการในส่วนนี้ กรุณาเลือกอย่างใดอย่างหนึ่ง ลงชื่อเข้าใช้ | ลงทะเบียน

รายละเอียดเครดิต

ข้อความล้วน|อุปกรณ์พกพา|ประวัติการแบน|G2GNet.com  

GMT+7, 2024-10-18 12:06 , Processed in 0.175265 second(s), 4 queries , File On.

Powered by Discuz! X3.4, Rev.62

Copyright © 2001-2020 Tencent Cloud.

ตอบกระทู้ ขึ้นไปด้านบน ไปที่หน้ารายการกระทู้