วิธีการใช้สาขาและผูกพันในภาษาการเขียนโปรแกรมการทำงานหรือไม่


26

ฉันพยายามเขียนสาขาและค้นหาขอบเขตในชุดของฟังก์ชั่นทั้งหมด f: D -> R ซึ่งขนาดโดเมนเล็ก (| D | ~ 20) และช่วงนั้นใหญ่กว่ามาก (| R | ~ 2 ^ 20 ) ตอนแรกฉันคิดวิธีแก้ปัญหาต่อไปนี้

(builder (domain range condlist partial-map)
            (let ((passed? (check condlist partial-map)))
              (cond
               ((not passed?) nil)
               (domain (recur-on-first domain range condlist partial-map '()))
               (t partial-map))))
(recur-on-first (domain range condlist partial-map ignored)
                   (cond
                    ((null range) nil)
                    (t (let ((first-to-first
                              (builder (cdr domain)
                                       (append ignored (cdr range))
                                       condlist
                                       (cons (cons (car domain) (car range)) partial-map))))
                         (or first-to-first
                             (recur-on-first domain
                                             (cdr range)
                                             condlist
                                             partial-map
                                             (cons (car range) ignored))))))))

นี่คือพารามิเตอร์condlistของฟังก์ชันbuilderคือรายการเงื่อนไขที่ควรได้รับการแก้ไขโดยโซลูชัน ฟังก์ชั่นcheckผลตอบแทนที่ศูนย์ IFF องค์ประกอบใด ๆ partial-mapในรายการของเงื่อนไขการละเมิดโดย ฟังก์ชันrecur-on-firstกำหนดองค์ประกอบแรกในโดเมนให้กับองค์ประกอบแรกในช่วงและพยายามสร้างโซลูชันจากที่นั่น ความล้มเหลวนี้recur-on-firstจะเรียกใช้ตัวเองเพื่อลองและสร้างโซลูชันที่กำหนดองค์ประกอบแรกในโดเมนให้กับองค์ประกอบอื่นนอกเหนือจากองค์ประกอบแรกในช่วง อย่างไรก็ตามต้องรักษารายการignoredที่เก็บองค์ประกอบที่ถูกทิ้งเหล่านี้ (เช่นองค์ประกอบแรกในช่วง) เนื่องจากอาจเป็นรูปภาพขององค์ประกอบอื่น ๆ ในโดเมน

มีสองปัญหาที่ฉันเห็นด้วยวิธีนี้ รายการแรกคือรายการignoredและrangeในฟังก์ชั่นrecur-on-firstนั้นมีขนาดค่อนข้างใหญ่และappendเป็นการดำเนินการที่มีราคาแพง ปัญหาที่สองคือความลึกของการเรียกซ้ำของโซลูชันขึ้นอยู่กับขนาดของช่วง

ดังนั้นฉันจึงคิดวิธีต่อไปนี้ซึ่งใช้ลิสต์ที่เชื่อมโยงเป็นทวีคูณเพื่อเก็บองค์ประกอบในช่วง ฟังก์ชั่นstart, nextและendสิ่งอำนวยความสะดวกเพื่อย้ำกว่ารายการที่เชื่อมโยงเป็นทวีคูณ

(builder (domain range condlist &optional (partial-map nil))
            (block builder
                   (let ((passed? (check condlist partial-map)))
                     (cond
                       ((not passed?) nil)
                       (domain (let* ((cur (start range))
                                      (prev (dbl-node-prev cur)))
                                 (loop
                                   (if (not (end cur))
                                     (progn
                                       (splice-out range cur)
                                       (let ((sol (builder (cdr domain)
                                                           range
                                                           condlist
                                                           (cons (cons (car domain) (data cur)) partial-map))))
                                         (splice-in range prev cur)
                                         (if sol (return-from builder sol)))
                                       (setq prev cur)
                                       (setq cur (next cur)))
                                     (return-from builder nil)))))
                       (t partial-map))))))

รันไทม์ของโซลูชันที่สองนั้นดีกว่ารันไทม์ของโซลูชันแรกมาก การappendดำเนินการในโซลูชันแรกจะถูกแทนที่ด้วยองค์ประกอบการต่อเชื่อมเข้าและออกจากรายการที่เชื่อมโยงสองเท่า (การดำเนินการเหล่านี้เป็นเวลาคงที่) และความลึกของการเรียกซ้ำขึ้นอยู่กับขนาดของโดเมนเท่านั้น แต่ปัญหาของฉันในการแก้ปัญหานี้ก็คือมันใช้Cรหัสสไตล์ ดังนั้นคำถามของฉันคือสิ่งนี้

มีโซลูชันที่มีประสิทธิภาพเท่ากับโซลูชันที่สอง แต่ไม่ได้ใช้setfโครงสร้างข้อมูลที่ไม่แน่นอนและไม่แน่นอนหรือไม่? ในคำอื่น ๆ มีวิธีการแก้ปัญหาการเขียนโปรแกรมการทำงานที่มีประสิทธิภาพสำหรับปัญหานี้หรือไม่

คำตอบ:


1

แนวคิดแรกที่อยู่ในใจ: ใช้วิธีการทั่วไปเหมือนกัน แต่แทนที่ลูปด้วยการเรียกแบบเรียกซ้ำ - หางซึ่งพารามิเตอร์เป็นรายการที่เชื่อมต่อสำหรับขั้นตอนต่อไปของการคำนวณหรือไม่ คุณไม่จำเป็นต้องแก้ไขรายการที่แต่งงานเพียงแค่สร้างรายการใหม่ในแต่ละขั้นตอน สิ่งนี้ยอมรับว่าไม่ใช่เวลาคงที่ แต่คุณต้องเดินรายการเพื่อหาสถานที่ที่จะประกบกัน มันอาจสามารถใช้งานโหนดส่วนใหญ่ได้อีกครั้งโดยเฉพาะอย่างยิ่งถ้าคุณสามารถใช้รายการที่เชื่อมโยงโดยลำพัง

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.