Just algorithm!
[C#] แก้ปัญหา 180 IQ ด้วย LINQ

สวัสดีครับ ไม่ได้เขียนใน Blog นี้นานมาก งานมันเยอะ (ข้ออ้าง Smiley)
ก่อนอื่นขอประชาสัมพันธ์
ผมมีแผนจะทำ Training ให้บริษัท
โดยจะเอาเนื้อหามาทำเป็น Blog ด้วย
เนื้อหาจะเกี่ยวกับวิธีการทำให้เขียน Program ได้ดีขึ้น
แต่ไม่ได้เขียนที่ Blog นี้นะครับ
จะไปเขียนที่ CoreSharp.net web community ของเพื่อนผมเองครับ Smiley
(ที่ไม่เขียนใน Blog นี้ เพราะ Target Audience เป็นผู้เขียน Program ทั่ว ๆ ไป
แต่ Blog นี้ เขียนตามความสะใจของเจ้าของ Blog Smiley)
ยังไงก็ติดตามนะครับ อัพเรื่อย ๆ

เพื่อน ๆ รู้จักเกม 180 IQ ไหมครับ (ถ้ารู้จักแปลว่าแก่แล้ว Smiley)
เป็นเกมที่จะให้เลขมาจำนวนนึง เช่น ให้เลข 1 2 5 8 มา
คุณจะ บวก ลบ คูณ หาร เลขสี่ตัวนี้ยังไง ให้ได้ผลลัพธ์ที่ต้องการ เช่น 27
คุณอาจจะเอา 8+5 ได้ 13 แล้วคูณด้วย 2 ได้ 26
แล้วบวก 1 ได้ 27
ง่ายไหมครับ? Smiley
ลองแก้ปัญหาดูสักข้อก่อนอ่านต่อไป
1 2 5 8 = 44

...

ทีนี้ลองคิดดูว่าคุณจะ Solve ปัญหานี้โดยใช้ Computer ยังไง
จากตัวอย่างด้านบน ((8+5)*2) + 1 = 27
คุณจะเห็นว่าเลข 1 2 5 8 มันสลับกันไปหมดการสลับนี้ เราเรียกว่า Permutation ครับ
คุณสามารถสลับ 1 2 5 8 ได้ 4! = 24 วิธี

ต่อมาดูที่เครื่องหมาย + - * / คุณอาจจะใช้ + - * / มากกว่า 1 ครั้งก็ได้
การสลับแบบที่ใช้ตัวเลือกได้มากกว่า 1 ครั้ง เราเรียกว่า Permutation with Repetition ครับ
คุณสามารถสลับ + - * / ได้ อย่างละ 3 ครั้ง เป็น 4^3 = 64 วิธี

ต่อมาดูที่วงเล็บ คุณสามารถสลับวงเล็บได้ 5 วิธี คือ
(((a b) c) d)
((a (b c)) d)
((a b) (c d))
(a ((b c) d))
(a (b (c d)))
วิธีการสลับวงเล็บแบบนี้เราเรียกว่า Binary Bracketing

สรุปว่า วิธีการทั้งหมดที่จะทำให้เกิดคำตอบมีทั้งหมด 24 * 64 * 5 = 7,680 วิธี
เนื่องจาก Search Space มันแค่หลักพัน เราก็ให้ Computer มันหาทุกวิธีเลย
แล้วเอาคำตอบออกมา

แล้วการทำ Permutation กะ Binary Bracketing เนี่ยทำยังไงล่ะครับ
อย่าไปเครียด ผมทำไว้ให้คุณแล้ว อิอิ
เชิญไป Download ที่ CodePlex ครับ Smiley
Library ชื่อ Combinatorics นะครับ
ผมทำไว้เป็น OpenSource ถ้าสนใจ Code ก็ลองเอาไปดูได้ว่า
Library สำหรับ Permutation กะ Binary Bracketing เนี่ย ทำยังไง

ก่อนอื่น ประกาศกลุ่มของตัวเลขก่อนครับ 1 2 5 8

var nums = new Expression[] {
                   Expression.Constant(1.0),
                   Expression.Constant(2.0),
                   Expression.Constant(5.0),
                   Expression.Constant(8.0) };


ต่อมาประกาศกลุ่มของ Operation คือ + - * /

var operations = new Func<Expression, Expression, Expression>[] {
                   Expression.Add,
                   Expression.Subtract,
                   Expression.Multiply,
                   Expression.Divide };


จะเห็นว่าผมประกาศเป็น Expression ทั้งหมด
เพราะผมต้องการแสดง Expression ของผลลัพธ์ด้วย
ถ้าคุณต้องการแค่ผลลัพธ์ ก็ใช้ double แทน Expression ไปเลย
ทำงานเร็วกว่ากันเยอะ
อ่านให้เข้าใจ รับรองประยุกต์ใช้ไม่ยาก

                //Permute ตัวเลขทั้งหมด
var solutions = from numsPermute in nums.Permute()

                //Permutation with Repetition operation
ทั้งหมด 3 ที
                from opsPermute in operations.Permute(3, CombinatoricModel.Repetition)

                //เอาตัวเลข และ operation ต่าง ๆ ไป
ทำ Binary Bracketing
                from results in numsPermute.BinaryBracketing(opsPermute)

                //
แปลง Expression เป็นผลลัพธ์
                let computed = Expression.Lambda<Func<double>>(results).Compile()()

                //
เลือกเฉพาะค่า 1 - 100
                where computed > 0.0 &&
                      computed <= 100.0 &&
                      Math.Floor(computed) == computed

                //
จัดกลุ่มตามผลลัพธ์
                group results by computed into g

                //
จัดเรียงตามผลลัพธ์
                orderby g.Key

                //
คืนค่า ผลลัพธ์ และ Expression ตัวแรก
                select string.Format("{0} = {1}", g.Key, g.First());

//
แสดงผล
solutions.ForEach(s => Console.WriteLine(s));
//1 = ((1 + (2 + 5)) / 8)
//2 = ((1 - (2 + 5)) + 8)
//3 = (1 + ((2 * 5) - 8))
//4 = (((1 + 5) * 2) - 8)
//5 = (((1 * 2) - 5) + 8)
//6 = (1 + ((2 - 5) + 8))
//7 = (((1 + 2) * 5) - 8)
//8 = (((1 - 5) + 8) * 2)
//9 = (((1 / 2) * 8) + 5)
//10 = (1 + (5 + (8 / 2)))
//11 = ((1 * (2 * 8)) - 5)
//12 = (((1 - 2) + 5) + 8)
//13 = (((1 + 8) * 2) - 5)
//14 = (((2 - 1) + 5) + 8)
//15 = (((1 * 2) + 5) + 8)
//16 = (1 + (2 + (5 + 8)))
//17 = (((2 * 5) - 1) + 8)
//18 = ((1 * (2 * 5)) + 8)
//19 = (1 + ((2 * 5) + 8))
//20 = (((1 / 2) * 5) * 8)
//21 = ((1 * (2 * 8)) + 5)
//22 = (1 + ((2 * 8) + 5))
//23 = (((1 + 2) * 5) + 8)
//24 = ((1 - 5) * (2 - 8))
//25 = (1 - ((2 - 5) * 8))
//26 = (1 * (2 * (5 + 8)))
//27 = (1 + (2 * (5 + 8)))
//28 = ((1 + (5 / 2)) * 8)
//29 = (((1 + 2) * 8) + 5)
//30 = (1 * (5 * (8 - 2)))
//31 = (1 - ((2 - 8) * 5))
//32 = (((1 - 2) + 5) * 8)
//33 = ((5 * (8 - 1)) - 2)
//34 = (2 - ((1 - 5) * 8))
//35 = (((1 - 2) + 8) * 5)
//36 = ((1 + 5) * (8 - 2))
//37 = (2 - ((1 - 8) * 5))
//38 = ((1 * (5 * 8)) - 2)
//39 = ((1 - 2) + (5 * 8))
//40 = ((2 - 1) * (5 * 8))
//41 = ((2 - 1) + (5 * 8))
//42 = ((1 * 2) + (5 * 8))
//43 = (1 + (2 + (5 * 8)))
//44 = (((1 / 2) + 5) * 8)
//45 = (((2 - 1) + 8) * 5)
//46 = (((1 + 5) * 8) - 2)
//47 = (((1 + 8) * 5) + 2)
//48 = (((2 - 1) + 5) * 8)
//49 = ((2 + 5) * (8 - 1))
//50 = (((1 * 2) + 8) * 5)
//51 = (1 + ((2 + 8) * 5))
//55 = ((1 + (2 + 8)) * 5)
//56 = (((1 * 2) + 5) * 8)
//57 = (1 + ((2 + 5) * 8))
//60 = ((1 + 5) * (2 + 8))
//63 = ((1 + 8) * (2 + 5))
//64 = ((1 + (2 + 5)) * 8)
//70 = (2 * (5 * (8 - 1)))
//72 = (((2 * 5) - 1) * 8)
//75 = (((2 * 8) - 1) * 5)
//78 = (2 * ((5 * 8) - 1))
//79 = ((2 * (5 * 8)) - 1)
//80 = (1 * (2 * (5 * 8)))
//81 = (1 + (2 * (5 * 8)))
//82 = ((1 + (5 * 8)) * 2)
//85 = ((1 + (2 * 8)) * 5)
//88 = ((1 + (2 * 5)) * 8)
//90 = ((1 + 8) * (2 * 5))
//96 = ((1 + 5) * (2 * 8))


แว๊ก! คำตอบออกมาเพียบเลย
จะเห็นว่าเขียนดี ๆ คุณสามารถแก้ปัญหา 180 IQ ได้ ด้วย Code LINQ ไม่เกิน 8 บรรทัด!!!
จบแล้วครับ ทีนี้จะหาเลขอะไรก็ง่าย ๆ แล้วใช่ไหมครับ Smiley


Create Date : 26 เมษายน 2552
Last Update : 26 เมษายน 2552 21:58:10 น. 6 comments
Counter : 8338 Pageviews.

 
ขอบคุณ นะ
ที่บอกให้
^_^


โดย: Grand IP: 118.174.132.241 วันที่: 15 สิงหาคม 2552 เวลา:17:34:26 น.  

 
Algorithm ที่ใช้ในการ generate permutation อยู่ตรงไหนเหรอครับ ผมสนใจมาก แต่ผมเขียน LINQ อะไรนี่ไม่เป็นนะครับ แค่อยากรู้ว่ามันจะทำงานได้เร็วกว่าการ implement แบบ บ้านๆ เยอะหรือไม่น่ะครับ


โดย: AlgoNerd IP: 202.151.7.30 วันที่: 8 กรกฎาคม 2553 เวลา:15:37:55 น.  

 
ไป download ที่ chaow.codeplex.com
แล้ว search class ชื่อ Permutation ดูครับ
วัด Performance แล้วได้ผลยังไงบอกด้วยนะครับ


โดย: chaowman วันที่: 12 กรกฎาคม 2553 เวลา:1:19:28 น.  

 
ตามมาอ่าน จากกระทู้ในพันทิบ
เยี่ยมมากครับ




โดย: zkaru IP: 180.210.216.131 วันที่: 26 สิงหาคม 2553 เวลา:12:50:35 น.  

 
ช่วยแนะนำหนังสือที่อธิบาย linq พร้อมตัวอย่างด้วยครับ

อยากรู้เกี่ยวกับ algorithm การใส่วงเล็บ (binary bracketing)

อ่านใน framework ของคุณแล้วไม่เข้าใจ เพราะไม่เคยเล่น linq แต่ sql ผมพอเข้าใจบ้าง

แล้วถ้าไม่ใช้ linq จะเขียน code อย่าไร อยากรู้มากๆครับ


โดย: โหน่ง IP: 183.89.33.130 วันที่: 19 กุมภาพันธ์ 2554 เวลา:12:21:51 น.  

 
คือผมทำไม่ได้อ่ะครับช่วยทำเป็นโปรแกรมให้หน่อยได้ไหมครับ ถึงว่าขอร้องแล้ว ครูผมให้ทำข้อละ 5 วิธี วี 20 ข้อ คิดไม่ได้เลย แล้วต้องส่งเร็วๆนี้อีก


โดย: ไม่รู้สินะ IP: 27.145.78.252 วันที่: 3 กุมภาพันธ์ 2558 เวลา:23:43:01 น.  

ชื่อ :
Comment :
  *ใช้ code html ตกแต่งข้อความได้เฉพาะสมาชิก
 

chaowman
Location :
กรุงเทพฯ Thailand

[Profile ทั้งหมด]

ให้ทิปเจ้าของ Blog [?]
ฝากข้อความหลังไมค์
Rss Feed
Smember
ผู้ติดตามบล็อก : 8 คน [?]





New Comments
Group Blog
 
All Blogs
 
Friends' blogs
[Add chaowman's blog to your web]
Links
 

 Pantip.com | PantipMarket.com | Pantown.com | © 2004 BlogGang.com allrights reserved.