|
โจทย์ข้อนี้ต้องการให้พิมพ์ X เป็นรูปพื้นที่สี่เหลี่ยมขนมเปียกปูน (Rhombus Area) โดยการรับค่าตัวเลขชนิดจำนวนเต็มแบบเลขคี่เข้ามา แล้วทำการพิมพ์ดังภาพตัวอย่าง ...
โจทย์ลักษณะแบบนี้ หากมองดูเผินๆค่อนข้างไร้สาระ เพราะนำไปใช้งานจริงไม่ได้ แต่ทว่าสำหรับแอดมินกลับมองเห็นเป็นความคลาสสิค คลาสสิคยังไงล่ะ??? ก็เพราะว่าคนส่วนใหญ่มักตีโจทย์โดยการคิดหาคำตอบแบบเดินหน้า (Forward Algorithm) คือพิมพ์คำตอบทีละบรรทัดน่ะซิ แต่หากคิดอีกแบบคือ การคิดย้อนกลับ (Backward Algorithm) ด้วยการมองไปที่คำตอบแบบรวมเอาไว้ทั้งหมด จากนั้นแยกวิเคราะห์เพื่อหาคำตอบกลับคืนไปทีละส่วนๆ เหมือนดั่งที่แอดมินจะนำมาอธิบายเอาไว้ในบทความชิ้นนี้ครับผม และความคลาสสิคอีกอย่างคือ เรานำหลักการวิธีคิดการมองภาพรวมเพื่อไปแก้ปัญหาโจทย์กับงานจริงๆได้แน่นอนครับ ... (อย่าลืมลองคิดหาวิธีอื่นๆด้วยล่ะ) ... หรืออ่านเสริมเรื่อง Working Backward Algorithm
ใช้ภาพประกอบจากทางด้านบน ... สิ่งแรกที่ต้องพิจารณา คือ จะรู้ได้อย่างไรว่าจำนวนตัวเลข (คี่) นั้นๆ มันอยู่ในลำดับที่เท่าไร??? และเพื่ออะไร??? ...
ลำดับที่ของเลขจำนวนเต็ม (คี่) = (ค่าอินพุท หารตัดเศษด้วย 2) + (ค่าอินพุท หารเอาเศษด้วย 2)
เช่น เลข 13 จะถูกจัดเรียงดังนี้ 1, 3, 5, 7, 9, 11, 13
ดังนั้นลำดับที่ของเลข 13 ...
= (13 \ 2) + (13 Mod 2)
= 6 + 1
= 7 --> นี่คือคำตอบ ซึ่งจะเป็นเงื่อนไขในการวนรอบ
เอ้า!!! แล้วคำตอบส่วนด้านล่างนั่นล่ะ มันหายไปไหน??? ... มันไม่ได้หายไปไหน แต่มันเป็นเงาของคำตอบที่อยู่ซีกด้านบน เพราะในเมื่อเราพิมพ์ส่วนด้านบนได้แล้ว ก็เอามันมาเป็นคำตอบในซีกด้านล่างซ่ะซิครับ จะไปคิดคำนวณหาให้เมื่อยก้นไปทำไมล่ะ จริงหรือเปล่า ... 5555+
FIRST ANALYSIS ...
- Dim S As String = ""
- Dim sArr(100) As String '// เก็บค่าคำตอบเงา
- For i As Integer = 1 To orderNum
- '// (1) คำตอบในการแสดงผล
- S = S + "X"
- '// เก็บค่าคำตอบเงา โดยเริ่มจาก Index = 0
- sArr(i - 1) = S
- '// แสดงผลคำตอบ พร้อมกับขึ้นบรรทัดใหม่
- Console.Write(S & vbCrLf)
- '// เพิ่ม "X" ไว้รออีก 1 ตัว เพราะค่าที่จะพิมพ์มันเป็นเลขคี่ เมื่อวนกลับไปที่ (1)
- S = S + "X"
- Next
คัดลอกไปที่คลิปบอร์ด สมมุติว่าค่าอินพุทที่รับเข้ามา คือ 5 ดังนั้น 1, 3, 5 ลำดับที่ของเลข 5 หรือ orderNum = 3
- รอบที่ 1 ... ค่า S เริ่มต้นจะว่างเปล่า จากนั้นเอา S = S & "X" คือการพิมพ์ X ออกไป 1 ตัว แต่ก่อนที่มันจะวนรอบกลับขึ้นไปก็เพิ่ม X เข้าไปต่อท้ายเป็น XX
- รอบที่ 2 ... ค่า S = "XX" จากนั้น S = S & "X" เมื่อนำไปต่อท้ายกับของเดิมคือ XX ก็จะกลายเป็นพิมพ์ XXX แต่ก่อนที่มันจะวนรอบกลับขึ้นไปก็เพิ่ม X เข้าไปต่อท้ายเป็น XXXX
- รอบที่ 3 ... ค่า S = "XXXX" จากนั้น S = S & "X" เมื่อนำไปต่อท้ายกับของเดิมคือ XXXX ก็จะกลายเป็นพิมพ์ XXXXX แต่ก่อนที่มันจะวนรอบกลับขึ้นไปก็เพิ่ม X เข้าไปต่อท้ายเป็น XXXXXX ...
เนื่องจากค่าสูงสุดในการวนลูปคือ 3 รอบ (orderNum = 3) ก็เป็นการสิ้นสุดการพิมพ์ในชุดแรก ... จากบรรทัดคำสั่ง sArr(i - 1) = S คือการเก็บค่าที่พิมพ์ออกไปทั้ง 3 ชุดเอาไว้ ก็นำมันกลับมาพิมพ์ใหม่อีกรอบ แต่เป็นการพิมพ์คำตอบแบบเรียงกลับด้านกัน
- For i = orderNum - 1 To 1 Step -1
- Console.Write(sArr(i - 1) & vbCrLf)
- Next
- XXX
- X
คัดลอกไปที่คลิปบอร์ด เราจะเริ่มต้นพิมพ์แบบกลับด้านกัน โดยเริ่มจากค่า Upper Bound หรือค่าสูงสุดของ Array แล้วลดค่าลงทีละ 1 (Step -1) แต่ตัดส่วนคำตอบแรกทิ้งไป i = orderNum - 1 เพื่อไม่ต้องพิมพ์ซ้ำ
SECOND ANALYSIS ...
ส่วนแรกแม้ว่าเราจะยังไม่ได้คำตอบตามที่โจทย์ต้องการ แต่มันคือจุดเริ่มต้นของการคิด วิเคราะห์ปัญหา แบบมีลำดับขั้นตอน ...
ให้ดู X แถวแรกบนสุดมันอยู่ตำแหน่งที่เท่าไร??? คำตอบคือ อยู่จุดกึ่งกลางของแถวที่ 3 ที่มีค่าสูงสุด และเนื่องจากว่ามันเป็นเลขคี่ เราลองกระจายลำดับเลขเล่นๆไป เช่น 1 2 3 4 5 เราจะสังเกตเห็นว่า จุดกึ่งกลางของเลขชุดนี้คือ 3 จะมีจำนวนตัวเลขที่อยู่ทางซ้ายและทางขวาเท่ากัน ... ตามนิยามกฏการสมมาตรอะไรประมาณนี้แหละครับ 5555+
ดังนั้นหากเราอยากรู้จุดกึ่งกลางของเลข 5 ก็คือการเอา (5 มาหารตัดเศษด้วย 2) + (5 หารเอาเศษด้วย 2) ก็คือ (5 \ 2) + (5 Mod 2) = 3 ... แต่โจทย์ต้องการให้เราพิมพ์ช่องว่าง (ASCII Code = 32 ฐาน 10) นำหน้า X เราจึงคิดเฉพาะส่วนแรกคือ 5 หารตัดเศษด้วย 2 ก็พอ
- For i As Integer = 1 To orderNum
- '// หาค่า Space นำหน้า ด้วยการหารตัดเศษ (โดยที่ค่า N จะลดค่าลงทีละ 2 เพราะมันเป็นเลขคี่ ... อยู่ด้านล่างใกล้ Next)
- For sP = 1 To (N \ 2)
- S = Chr(32) & S
- Next
- '// (1) เอา Space นำหน้าตามด้วยคำตอบ
- S = S + "X"
- '// เก็บค่าคำตอบเงา โดยเริ่มจาก Index = 0
- sArr(i - 1) = S
- '// แสดงผลคำตอบ พร้อมกับขึ้นบรรทัดใหม่
- Console.Write(S & vbCrLf)
- '// เพิ่ม "X" ไว้รออีก 1 ตัว เพราะค่าที่จะพิมพ์มันเป็นเลขคี่ เมื่อวนกลับไปที่ (1)
- '// ตัดค่าช่องว่างออกไป เพราะจะวนไปรับค่า Space หรือ Chr(32) ใหม่
- S = Trim(S & "X")
- '// ลดค่าอินพุทลงไปทีละ 2 เพราะเป็นเลขคี่ เช่นจาก 5 ก็จะเหลือ 3 และเหลือ 1 เพื่อสิ้นสุด
- N = N - 2
- Next
คัดลอกไปที่คลิปบอร์ด ดังนั้นเราเพิ่มโค้ดใส่ช่องว่างนำหน้าเข้าไปก่อนการพิมพ์ โดยจำนวนช่องว่างที่ต้องพิมพ์ sP = 1 To (N \ 2)
- รอบที่ 1 ... sP = 1 To (5 \ 2) = 2 คือพิมพ์ Chr(32) หรือช่องว่างนำหน้าไป 2 ตัว เมื่อพิมพ์เสร็จลดค่ามันลงไป 2 ก็จะเป็น N = 5 - 2 = 3
- รอบที่ 2 ... sP = 1 TO (3 \ 2) = 1 คือพิมพ์ Chr(32) หรือช่องว่างนำหน้าไป 1 ตัว เมื่อพิมพ์เสร็จลดค่ามันลงไป 2 ก็จะเป็น N = 3 - 2 = 1
- รอบที่ 3 ... sP = 1 TO (1 \ 2) = 0 คือไม่มีการพิมพ์ Chr(32) หรือช่องว่างใดๆออกมา ... และมันเป็นจังหวะเดียวกับที่ orderNum = 3 จะเป็นการวนรอบในครั้งสุดท้ายพอดี ... ก็จบบริบูรณ์
มาดูโค้ดฉบับเต็ม VB.NET ...
- ' / --------------------------------------------------------------------------------
- ' / Developer : Mr.Surapon Yodsanga (Thongkorn Tubtimkrob)
- ' / eMail : thongkorn@hotmail.com
- ' / URL: http://www.g2gnet.com (Khon Kaen - Thailand)
- ' / Facebook: https://www.facebook.com/g2gnet (For Thailand)
- ' / Facebook: https://www.facebook.com/commonindy (Worldwide)
- ' / Purpose: How to solve problems in programming.
- ' / Microsoft Visual Basic .NET (2010)
- ' /
- ' / This is open source code under @CopyLeft by Thongkorn Tubtimkrob.
- ' / You can modify and/or distribute without to inform the developer.
- ' / --------------------------------------------------------------------------------
- Module Module1
- Sub Main()
- Console.Clear()
- Dim orderNum As Integer
- Console.Write("Enter number: ")
- Dim N As Integer = Console.ReadLine()
- '// หาลำดับที่ของตัวเลข ด้วยการ (จำนวนหารตัดเศษด้วย 2)+(จำนวนหารเอาเศษด้วย 2) ... จะเป็นค่าสูงสุดในการวนรอบ
- orderNum = (N \ 2) + (N Mod 2)
- Console.WriteLine("The order is {0}", orderNum)
- Call FirstMethod(N, orderNum)
- Call SecondMethod(N, orderNum)
- End Sub
- Sub FirstMethod(ByVal N As Integer, orderNum As Integer)
- Dim S As String = ""
- Dim sArr(100) As String '// เก็บค่าคำตอบเงา
- For i As Integer = 1 To orderNum
- '// (1) คำตอบในการแสดงผล
- S = S + "X"
- '// เก็บค่าคำตอบเงา โดยเริ่มจาก Index = 0
- sArr(i - 1) = S
- '// แสดงผลคำตอบ พร้อมกับขึ้นบรรทัดใหม่
- Console.Write(S & vbCrLf)
- '// เพิ่ม "X" ไว้รออีก 1 ตัว เพราะค่าที่จะพิมพ์มันเป็นเลขคี่ เมื่อวนกลับไปที่ (1)
- S = S + "X"
- Next
- For i = orderNum - 1 To 1 Step -1
- Console.Write(sArr(i - 1) & vbCrLf)
- Next
- Console.ReadLine()
- End Sub
- Sub SecondMethod(ByVal N As Integer, orderNum As Integer)
- Dim S As String = ""
- Dim sP As Integer = orderNum - 1
- Dim sArr(100) As String
- For i As Integer = 1 To orderNum
- '// หาค่า Space นำหน้า ด้วยการหารตัดเศษ (โดยที่ค่า N จะลดค่าลงทีละ 2 เพราะมันเป็นเลขคี่ ... อยู่ด้านล่างใกล้ Next)
- For sP = 1 To (N \ 2)
- S = Chr(32) & S
- Next
- '// (1) เอา Space นำหน้าตามด้วยคำตอบ
- S = S + "X"
- '// เก็บค่าคำตอบเงา โดยเริ่มจาก Index = 0
- sArr(i - 1) = S
- '// แสดงผลคำตอบ พร้อมกับขึ้นบรรทัดใหม่
- Console.Write(S & vbCrLf)
- '// เพิ่ม "X" ไว้รออีก 1 ตัว เพราะค่าที่จะพิมพ์มันเป็นเลขคี่ เมื่อวนกลับไปที่ (1)
- '// ตัดค่าช่องว่างออกไป เพราะจะวนไปรับค่า Space หรือ Chr(32) ใหม่
- S = Trim(S & "X")
- '// ลดค่าอินพุทลงไปทีละ 2 เพราะเป็นเลขคี่ เช่นจาก 5 ก็จะเหลือ 3 และเหลือ 1 เพื่อสิ้นสุด
- N = N - 2
- Next
- '// แสดงผลส่วนเงา
- For i = orderNum - 1 To 1 Step -1
- Console.Write(sArr(i - 1) + vbCrLf)
- Next
- Console.ReadLine()
- End Sub
คัดลอกไปที่คลิปบอร์ด
มาดูโค้ดฉบับเต็ม C# ...
ขอให้สังเกตการวนรอบเพื่อพิมพ์ช่องว่าง คราวนี้แอดมินเปลี่ยนใหม่เป็น การใช้ค่าลำดับตัวเลขของอินพุทเป็นเงื่อนไขแทน หากเราพิจารณาจากรูปประกอบทางด้านบนจะเห็นได้ว่า จำนวนช่องว่างจะเริ่มต้นจากค่าลำดับตัวเลข - 1 จากนั้น มันก็จะถูกลดค่าลงหนึ่งเสมอทุกๆครั้งที่วนรอบกลับมา ... อั้ยย่ะ!!!- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Text;
- namespace BasicThinkingCSharp
- {
- class Program
- {
- static void Main(string[] args)
- {
- int orderNum = 0;
- Console.Write("Enter number: ");
- string n = Console.ReadLine();
- orderNum = (Int32.Parse(n) / 2) + (Int32.Parse(n) % 2);
- Console.WriteLine("The order is {0}", orderNum);
- firstmethod(Int32.Parse(n), orderNum);
- }
- static void firstmethod(int m, int order) {
- string s = "";
- int sp = order-1;
- string[] sArr = new string[100];
- for (int i = 1; i <= order; i++) {
- for (int j = 1; j <= sp; j++) s = " " + s;
- s = s + "X";
- sArr[i] = s;
- Console.Write(s + "\n");
- s = s.Replace(" ", "");
- s = s + "X";
- sp--;
- }
- for (int i = order-1; i >= 0; i--) Console.Write(sArr[i] + "\n");
- Console.ReadLine();
- }
- }
- }
คัดลอกไปที่คลิปบอร์ด
วิธีคิดหาคำตอบแบบเดินหน้า (VB.NET)
ก็คือการพิมพ์แบบทีละบรรทัด โดยเริ่มจากบรรทัดแรกบนสุด ซึ่งจะมีช่องว่างเริ่มต้นจาก (ลำดับที่ตัวเลข - 1) ... แอดมินคิดว่าในเรื่องนี้คงไม่ต้องอธิบายมากมาย เพราะเชื่อว่าหลายๆคนคงต้องคิดแบบลักษณะนี้กันอยู่แล้วแหละข่ะรับกระผม
- Sub ThirdMethod(ByVal N As Integer, orderNum As Integer)
- Dim S As String = ""
- Dim sP As Integer = orderNum - 1
- Dim L As Integer = 1
- For i As Integer = 1 To orderNum
- For k As Integer = 1 To sP
- '// จำนวนช่องว่าง
- S = S & " "
- Next
- For j As Integer = 1 To L
- S = S & "X"
- Next
- Console.WriteLine(S)
- L += 2 : sP -= 1 : S = ""
- Next
- '// ทำกลับด้าน
- sP = 1
- L = N - 2
- For i As Integer = orderNum - 1 To 1 Step -1
- For k As Integer = 1 To sP
- '// จำนวนช่องว่าง
- S = S & " "
- Next
- For j As Integer = 1 To L
- S = S & "X"
- Next
- Console.WriteLine(S)
- L -= 2 : sP += 1 : S = ""
- Next
- Console.ReadLine()
- End Sub
คัดลอกไปที่คลิปบอร์ด
วิธีคิดหาคำตอบแบบเดินหน้า (C#)
- // การคิดแบบเดินหน้าหาคำตอบ (Forward Algorithm)
- static void secondmethod(int m, int order) {
- string s = "";
- int sp = order - 1;
- int x = 1;
- for (int i = 1; i <= order; i++) {
- for (int j = 1; j <= sp; j++) s = s + " ";
- for (int k = 1; k <= x; k++) s = s + "X";
- Console.WriteLine(s);
- x += 2; sp -= 1; s = "";
- }
- sp = 1;
- x = m - 2;
- for (int i = order-1; i >= 1; i--) {
- for (int j = 1; j <= sp; j++) s = s + " ";
- for (int k = 1; k <= x; k++) s = s + "X";
- Console.WriteLine(s);
- x -= 2; sp += 1; s = "";
- }
- Console.ReadLine();
- }
คัดลอกไปที่คลิปบอร์ด Conclusion: จะเห็นได้เลยว่าการแก้ปัญหาโจทย์ข้อนี้ไม่ได้ใช้กฏสมการ หรือการคำนวณอะไรที่ซับซ้อนใดๆเลย ใช้เพียงแต่คำว่า "พื้นฐาน" เท่านั้นเอง ... สวัสดี
|
|