ฉันมีตารางเรียงต่อกันของขนาด จำกัด ที่ทราบซึ่งก่อตัวเป็นแผนที่ แผ่นบางแผ่นที่อยู่ในแผนที่จะถูกวางลงในชุดที่รู้จักกันในชื่ออาณาเขต ดินแดนนี้เชื่อมต่อกัน แต่ไม่มีใครรู้เกี่ยวกับรูปร่างของมัน ส่วนใหญ่มันจะเป็นหยดปกติ แต่อาจยืดออกไปได้ในทิศทางเดียวและอาจมีรูได้ ฉันสนใจที่จะค้นหาชายแดน (ด้านนอก) ของอาณาเขต
นั่นคือฉันต้องการรายการของกระเบื้องทั้งหมดที่แตะหนึ่งในกระเบื้องในดินแดนโดยที่ตัวเองไม่ได้อยู่ในดินแดน วิธีที่มีประสิทธิภาพในการค้นหาสิ่งนี้คืออะไร?
สำหรับความยากเป็นพิเศษมันเกิดขึ้นที่ไทล์ของฉันเป็น hexes แต่ฉันคิดว่ามันไม่ได้สร้างความแตกต่างมากนักแต่ละไทล์ยังคงมีพิกัด x และ y เป็นจำนวนเต็มและถ้ามีไทล์ฉันสามารถหาเพื่อนบ้านได้อย่างง่ายดาย ด้านล่างเป็นตัวอย่างบางส่วน: สีดำคืออาณาเขตและเส้นขอบสีน้ำเงินที่ฉันต้องการค้นหา สิ่งนี้ในตัวของมันเองไม่ใช่ปัญหาที่ยากเลยอัลกอริธึมง่ายๆสำหรับสิ่งนี้ใน pseudo-python คือ:
def find_border_of_territory(territory):
border = []
for tile in territory:
for neighbor in tile.neighbors():
if neighbor not in territory and neighbor not in border:
border.add(neighbor)
อย่างไรก็ตามมันช้าและฉันต้องการบางสิ่งที่ดีกว่า ฉันมี O (n) วนรอบอาณาเขตอีกวงหนึ่ง (อันสั้น แต่ก็ยัง) เหนือเพื่อนบ้านทั้งหมดจากนั้นฉันต้องตรวจสอบการเป็นสมาชิกของสองรายการซึ่งหนึ่งในนั้นคือขนาด n นั่นทำให้สเกลของ O (n ^ 2) แย่มาก ฉันสามารถลดให้เป็น O (n) ได้โดยใช้ชุดแทนที่จะเป็นรายการสำหรับเส้นขอบและอาณาเขตเพื่อให้สมาชิกตรวจสอบได้อย่างรวดเร็ว แต่ก็ยังไม่ยอดเยี่ยม ฉันคาดหวังว่าจะมีหลายกรณีที่พื้นที่มีขนาดใหญ่ แต่ชายแดนมีขนาดเล็กเนื่องจากพื้นที่เรียบง่ายเทียบกับการขยายขนาดของเส้น ตัวอย่างเช่นหากอาณาเขตเป็นเลขฐานสิบหกของรัศมี 5 จะมีขนาด 91 แต่เส้นขอบจะมีขนาดเท่ากับ 36
ทุกคนสามารถเสนอสิ่งที่ดีกว่าได้ไหม
แก้ไข:
เพื่อตอบคำถามบางข้อด้านล่าง ขอบเขตสามารถมีขนาดตั้งแต่ประมาณ 20 ถึง 100 หรือมากกว่านั้น ชุดของแผ่นกระเบื้องที่สร้างอาณาเขตเป็นคุณลักษณะของวัตถุและเป็นวัตถุที่ต้องการชุดของแผ่นกระเบื้องชายแดนทั้งหมด
เริ่มแรกอาณาเขตจะถูกสร้างเป็นบล็อกแล้วส่วนใหญ่จะได้รับไพ่ทีละส่วน ในกรณีนี้มันเป็นความจริงที่ว่าวิธีที่เร็วที่สุดคือการเก็บชุดของเส้นขอบไว้และอัปเดตเฉพาะบนไทล์ที่ได้รับมา ในบางครั้งอาจมีการเปลี่ยนแปลงครั้งใหญ่ในอาณาเขตดังนั้นจึงจำเป็นต้องคำนวณใหม่อย่างเต็มที่
ตอนนี้ฉันเห็นว่าการทำอัลกอริธึมการค้นหาเส้นขอบอย่างง่ายเป็นทางออกที่ดีที่สุด ความซับซ้อนเพิ่มเติมเพียงอย่างเดียวที่เพิ่มขึ้นนี้คือการตรวจสอบให้แน่ใจว่ามีการคำนวณเส้นขอบใหม่ทุกครั้งที่อาจจำเป็นต้องมี แต่ไม่มากไปกว่านั้น ฉันค่อนข้างมั่นใจว่าสิ่งนี้สามารถทำได้อย่างน่าเชื่อถือในกรอบปัจจุบันของฉัน
สำหรับเวลาในรหัสปัจจุบันของฉันฉันมีกิจวัตรบางอย่างที่ต้องตรวจสอบไทล์ของดินแดนทั้งหมด ไม่ใช่ทุกเทิร์น แต่เป็นการสร้างและบางครั้งหลังจากนั้น มันใช้เวลามากกว่า 50% ของเวลาทำงานในชุดทดสอบของฉันถึงแม้ว่ามันจะเป็นส่วนเล็ก ๆ ของโปรแกรมที่สมบูรณ์ ดังนั้นฉันจึงกระตือรือร้นที่จะลดจำนวนซ้ำ ๆ อย่างไรก็ตามรหัสทดสอบเกี่ยวข้องกับการสร้างวัตถุมากกว่าการรันโปรแกรมปกติ (ตามธรรมชาติ) ดังนั้นฉันจึงรู้ว่านี่อาจไม่เกี่ยวข้องกันมากนัก