เฉลยโจทย์จาก Contest CodeAlgo 2025 ฉบับสั้นๆ
เฉลยโจทย์ของ CodeAlgo 2025 แบบย่อๆเหลือแต่เนื้อ (แต่ไม่มีโค้ดให้นะไปคิดเอง) ฉบับเต็มคงยังไม่ทำ ถ้าไม่มีใคร request มาเพราะมันจะละเอียดมาก


บันไดงูอย่างง่าย (Snake and Ladder Trial Edition)
โจทย์ข้อ 1 บันไดงูอย่างง่ายข้อนี้เป็นการเริ่มเดินจากช่องที่ 1 ไปให้ถึงช่องที่ โดยให้เดินน้อยครั้งที่สุด ซึ่งการเดินให้น้อยที่สุดก็แปลว่า แต่ละครั้งที่เดินก็ต้องไปให้ได้หลายช่องมากที่สุดเหมือนกัน
ดังนั้นจากช่องแรก ยังไงก็จะเดิน 5 ช่องก่อนเลยแน่ๆ และเมื่อเราลงที่ช่องที่ 6 เราก็จะสลับไปใช้ลูกเต๋าอีกลูกที่มีเลข 6 แล้ว หลังจากนั้นก็จะเดินแต่ 6 ช่องไปเรื่อยๆจนถึงเส้นชัย ทำให้ต้องเดินทั้งหมด ครั้ง เพราะเดินเลยเส้นชัยไปก็ได้
สามเหลี่ยมปาสคาล (Pascal Triangle)
โจทย์ข้อ 2 สามเหลี่ยมปาสคาลก็เขียนตามโจทย์เลยนั่นแหละ ไม่ได้มีทริกอะไรเลย
จมน้ำ (Drown)
โจทย์ข้อ 3 จมน้ำด้วยความที่ความสูงจะอยู่เท่าเดิมจนกว่าจะมีข้อมูลใหม่เข้ามา แทนที่เราจะต้องค่อยๆตรวจข้อมูลความสูงในทุกวินาทีตามที่โจทย์ให้มา เราก็ไปดูแค่วินาทีสุดท้ายก่อนที่ความสูงจะมีการเปลี่ยนแปลงก็ได้ เพราะถ้าคนใดคนหนึ่งจะจม จะคำนวณตอนวินาทีที่จมจริงๆ หรือวินาทีสุดท้ายก่อนความสูงเปลี่ยนก็ไม่ต่างกัน (เพราะจมอยู่ดีเนื่องจากน้ำมันขึ้นเรื่อยๆ)
ทำให้ถ้าเรามีข้อมูลชุดนึงว่าอยู่ที่ตำแหน่งความสูง 10 ตอนเวลา หน่วย และอยู่สูง 20 หน่วยตอนเวลา หน่วย เราก็แค่ดูว่าตอนเวลา หน่วยนั้น อยู่ที่ความสูง 10 ยังรอดอยู่ไหมก็พอ ซึ่งเราก็ทำแบบนี้ไปกับทุกคู่ชุดข้อมูลที่เรามี ของทุกๆคนก็ได้แล้ว
ตัวต่อ (Kindergarten Lego)
โจทย์ข้อ 4 ตัวต่อก่อนอื่นต้องคิดก่อนว่าเราใส่ตัวต่อลงไปได้มากสุดกี่ตัว
ซึ่งวิธีใส่ให้ได้เยอะที่สุดคือการวางตัวต่อที่กินพื้นที่น้อยที่สุดเท่าที่เป็นไปได้โดยยังไม่ได้ไปทับกับใคร(หรือโดนอันอื่นทับ)
ถ้าลองสมมติว่าแผ่นกระดานเป็น ตารางขนาด เราจะวางตัวขนาด ลงไปก่อน แล้วตามด้วย ไปเรื่อยๆจนถึงชิ้นที่มีขนาด เราจะได้ว่าใส่ได้มากสุดแค่ ชิ้นเท่านั้น
ถ้าเราใช้หลักการเดียวกันไปคิดกับตาราง ก็จะได้คำตอบคล้ายๆกันคือใส่ได้ ชิ้น
ทีนี้ลองมาคิดว่าจะแบ่งพื้นที่ให้ตัวยังไงดีหลังจากรู้ว่าจะวางกี่ชิ้นแล้ว
ลองดูตัวอย่างนี้นิดนึงลองกัน:
การคำนวณว่าวางได้กี่แบบสามารถแปลงเป็นการลากเส้นบนสี่เหลี่ยมทั้งสองด้านได้
จะเห็นว่าจริงๆแล้ว เราแค่ต้องลากเส้นบนตารางเอง ซึ่งก็คำนวณได้ไม่ยากด้วย combinatoric
กลับบ้าน (Place to Call Home)
โจทย์ข้อ 5 กลับบ้านเนื่องจากว่าแต่ละเขตเกี่ยวข้องกันกับแค่เขตที่อยู่ติดกันเท่านั้น แปลว่าตอนที่ดูว่าไปที่เขต ของแต่ละหมู่บ้านได้กี่วิธี เราก็จำเป็นต้องรู้แค่ว่าเรามาจากเขต ได้กี่วิธีก็พอ แต่ถึงอย่างนั้นก็ยังต้องรู้อยู่ดีว่าการที่เขต มันเดินมาได้กี่แบบ
ซึ่งข้อมูลจำนวนรูปแบบการเดิน เราสามารถเก็บข้อมูลด้วย matrix ได้ เช่น
เราสามารถแทนว่าตอนนี้เราสามารถเดินไปเมืองที่ 1 และ 2 ได้อย่างละ 1 วิธี
ทีนี้การจะคำนวณหาจำนวนวิธีของเขตถัดไปก็ทำได้โดยการดูว่าหมู่บ้านหนึ่งๆ สามารถมาจากหมู่บ้านไหนได้บ้างอย่างเช่นถ้าบอกว่าหมู่บ้านที่ 1 สามารถเดินทางจากหมู่บ้านที่ 1 หรือ 2 ก็ได้ คำตอบในเขตถัดไปก็จะเป็นการเอาจำนวนวิธีการเดินทางไปหมู่บ้านที่ 1 บวกกับของหมู่บ้านที่ 2 ซึ่งเราก็สามารถนำมาแปลงเป็น matrix เพื่อให้คำนวณทุกหมู่บ้านรวดเดียวได้แบบนี้:
เพื่อที่ว่าตอนคำนวณ
พอมันมีหลายเขตเข้าหน่อยมันก็กลายเป็นว่าต้องคูณ matrix ที่ใช้คำนวณวิธีซ้ำๆหลายๆรอบ ก็เลยต้องทำการคำนวณ exponent แทน
โจทย์ก็เลยกลายเป็นการคำนวณ matrix แทน ที่เราก็ทำได้ด้วยเทคนิกชื่อ Fast Exponentiation เพื่อให้คำนวณได้เร็วขึ้น
บันไดงู (Snake and Ladder Super Ultra Deluxe)
โจทย์ข้อ 6 บันไดงู (Ultra Deluxe)เราจะมาดูว่าการหาค่าของคำถามเดียวนั้นทำยังไงกันก่อน
สมมติให้ เป็นแต้มที่ได้มากที่สุดจากการเดินทั้งหมด ครั้ง และเริ่มที่ช่องที่ เราจะได้ว่าถ้าเดินได้ ถึง ช่องแล้ว ค่าจะเป็น
ด้วยความที่เราต้องดูข้อมูลแค่ช่วงระหว่าง ถึง เราสามารถใช้ Monotonic Queue ในการไล่เก็บว่าช่องไหนที่มีค่ามากที่สุดในช่วงๆนั้นได้ แทนการใช้ heap ในการเก็บข้อมูลค่ามากที่สุด
ทีนี้พอเวลาเจอหลายคำถาม ด้วยความที่จะหาคำตอบใหม่เรื่อยๆมันเสียเวลา เราจะเก็บคำถามทั้งหมดก่อน แล้วค่อย sort ไล่ตามจำนวนตาในการเล่น แล้วคำนวณไปเรื่อยๆพอจำนวนตาในการเดินเท่ากับคำถามไหน ก็จะตอบคำถามนั้น
- ถ้าผู้เล่นเป็นคนที่ 1 (หมากขาว) ก็จะได้ว่าเอาค่า มาบวกได้ตรงๆ ในคำถามนั้นเลย
- ถ้าผู้เล่นเป็นคนที่ 2 (หมากดำ) ก็จะได้ว่าทำแบบเดียวกัน แต่หาค่าเป็น เป็นสมการ แทนในคำถามนั้น
แต่ก็จะยังมีเคสดักเล็กน้อยคือ บางครั้งไม่ว่าเดินยังไงก็เดินไม่ถึงเส้นชัย บางครั้งอาจจะจงใจเดินให้ครบแบบไม่ถึงเส้นชัย บางครั้งเดินยังไงก็เลยเส้นชัย
ในเรื่อง memory สามารถลดจาก ช่องเหลือ ช่องได้โดยการสลับมิติแรกให้เหลือ 2 เพื่อใช้สลับระหว่าง กับ ได้เพราะมีการใช้มิติก่อนหน้าแค่ 1 อาเรย์ (เนื่องจากก้าวไปแค่ทีละก้าว)
ส่วนพอได้คำคอบครบแล้ว ก็จะพิมพ์เรียงตามลำดับตามคำถามที่ได้มาตอนแรกเลย
หนีไปดวงจันทร์ (Moving to the Moon)
โจทย์ข้อ 7 หนีไปดวงจันทร์ลองมาดูก่อนว่าการจะเลือกแบ่งของชิ้นเดียวนั้น ทำยังไงให้ดีที่สุด
สมมติมีของน้ำหนัก และแบ่งเป็น ส่วน (หลังจากนี้จะเรียกว่า ) วิธีที่ดีที่สุดคือเราจะแบ่งทุกชิ้นให้น้ำหนักเท่ากันก่อน () แล้วเอาเศษน้ำหนักที่เหลืออีก หน่วย ไปกระจายใส่ให้ของที่เหลือให้กลายเป็น หน่วย ถ้าแบ่งวิธีอื่น cost ที่ได้จะไม่ได้ค่าน้อยที่สุด (ไปทดสอบเองได้)
ทีนี้จะได้ว่า cost ที่ได้จากการตัดแบ่ง คือ
สำหรับวิธีการแบ่งว่าเราควรแบ่งของแต่ละชิ้นกี่ครั้งดี จะเริ่มจากแบ่ง 0 ครั้งไปจนถึง ครั้ง และจะดูจากว่าในของทุกชิ้น อันไหนที่ค่า หรือ cost ที่ลดได้ มีค่ามากที่สุดเท่าที่ทำได้ โดยที่ คือน้ำหนักและจำนวนการตัดแบ่งของชิ้นที่ ขณะนั้น ซึ่งค่า cost ที่ลดได้ จะไม่มีทางเพิ่มขึ้นถ้าแบ่งต่อไปเรื่อยๆ (อีกแหละ ไปลองทดสอบเองได้)
ส่วนว่าจะใช้การแบ่งรวมทั้งหมดกี่ครั้งจะเทียบ cost ที่ลดได้จากการแบ่ง เอาไปเทียบกับ cost ที่เพิ่มจากการแบ่งเพิ่มอีก 1 ชิ้นแล้วดูว่ามันคุ้มไหมที่จะแบ่งต่อ ซึ่งก็สามารถใช้ Priority Queue เพื่อดูว่า cost ที่ลดได้ในการแบ่งที่ดีที่สุด ณ ตอนนี้เป็นเท่าไหร่ แล้วก็เทียบกับค่าใช้จ่ายในการแบ่งไปเรื่อยๆก็ได้
แต่ถ้าลองส่งไปดู จะเห็นได้ว่าการแบ่งยังมีประสิทธิภาพไม่เพียงพอ เราเลยจะใช้จุดที่บอกว่าค่า cost ที่ลดได้ จะไม่มีทางเพิ่มขึ้น
ทำให้สามารถใช้ binary search บนค่า cost ที่ลดได้ () ****แล้วไป binary search ซ้ำอีกรอบบนของแต่ละชิ้นเพื่อหาว่าของแต่ละอันต้องแบ่งไปมากที่สุดกี่ครั้ง () เพื่อให้ค่า cost ในการส่งที่ลดในการตัดครั้งถัดไป มันยังไม่น้อยไปกว่า หรือก็คือหาค่า และ ของของแต่ละชิ้นที่ ยังไม่น้อยกว่า
ทีนี้เราจะเพิ่มหรือลดค่า ตอน Binary Search โดยดูจากเงื่อนไขว่า
- ในการตัดแบ่งไปเนี่ย ทั้งหมดใช้รวมกี่ครั้ง () โดยที่ต้องไม่มากกว่า เพราะโจทย์กำหนดว่าห้ามเกิน
- cost ที่ลดได้ยังไม่น้อยกว่า cost ที่เพิ่มจากการแบ่ง ครั้งเพิ่มอีก 1 ครั้ง
ถ้าเข้าเงื่อนไขทั้งสองอัน แสดงว่าเราต้องแบ่งเพิ่มเพราะยังลด cost ได้อีกโดยลดค่า แต่ถ้าผิดเงื่อนไขสัก 1 ข้อหมายความว่าใช้การแบ่งมากเกินไป ทำให้ต้องลดการแบ่งลงมาโดยการเพิ่มค่า
พอได้วิธีการตัดแบ่งที่ optimal สุดจากการ binary search ค่า แล้ว ก็เอาวิธีตัดแบ่งนั้นมาหาค่า cost ว่าเหลือเท่าไหร่ แล้วก็ตอบได้เลย
ขอบคุณที่ให้ความสนใจในการแข่งขัน code algo 2025 นะครับ
งานแข่งนี้เป็นการจัดขึ้นมาเป็นครั้งแรกของทีม ถ้าหากมีความเห็นหรือคำแนะนำเกี่ยวกับการแข่งขันในครั้งนี้สามารถบอกใน google form ด้านล่างนี้ได้เลยครับ
ขอบคุณครับ
ทีม Practical Algorithm