ฉันพยายามเขียนสาขาและค้นหาขอบเขตในชุดของฟังก์ชั่นทั้งหมด 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
โครงสร้างข้อมูลที่ไม่แน่นอนและไม่แน่นอนหรือไม่? ในคำอื่น ๆ มีวิธีการแก้ปัญหาการเขียนโปรแกรมการทำงานที่มีประสิทธิภาพสำหรับปัญหานี้หรือไม่