การตรวจจับการชนกันเป็น O เสมอ (n ^ 2)


14

เครื่องยนต์ฟิสิกส์สามารถลดความซับซ้อนนั้นได้หรือไม่โดยการจัดกลุ่มวัตถุที่อยู่ใกล้กันและตรวจสอบการชนภายในกลุ่มนี้แทนที่จะเทียบกับวัตถุทั้งหมดหรือไม่ (ตัวอย่างเช่นวัตถุที่อยู่ไกลสามารถลบออกจากกลุ่มโดยดูที่ความเร็วและระยะทางจากวัตถุอื่น)

ถ้าไม่นั่นทำให้เกิดการปะทะกันเล็กน้อยสำหรับทรงกลม (ใน 3d) หรือดิสก์ (เป็น 2d) หรือไม่ ฉันควรสร้างวงคู่หรือสร้างอาร์เรย์ของคู่แทน?

แก้ไข: สำหรับเครื่องยนต์ฟิสิกส์เช่นกระสุนและ box2d การตรวจจับการชนยังคงเป็น O (N ^ 2) หรือไม่


12
สองคำ: การแบ่งเชิงพื้นที่
MichaelHouse


1
พนันได้เลย. ฉันเชื่อว่าทั้งสองมีการใช้งานของ SAP ( Sweep และพรุน ) (ในหมู่อื่น ๆ ) ซึ่งเป็นอัลกอริทึม O (n log (n)) ค้นหา "การตรวจจับการชนกันของระยะกว้าง" เพื่อเรียนรู้เพิ่มเติม
MichaelHouse

2
@ Byte56 การกวาดและลูกพรุนมีความซับซ้อน O (n log (n)) เฉพาะในกรณีที่คุณต้องการเรียงลำดับทุกครั้งที่คุณทดสอบ คุณต้องการเก็บรายการสิ่งของที่เรียงลำดับไว้และทุกครั้งที่คุณเพิ่มรายการเพียงเรียงลำดับไปยังตำแหน่งที่ถูกต้อง O (บันทึก (n)) ดังนั้นคุณจะได้รับ O (บันทึก (n) + n) = O (n) มันซับซ้อนมากเมื่อวัตถุเริ่มเคลื่อนที่แม้ว่า!
MartinTeeVarga

1
@ SM4 ถ้าการเคลื่อนไหวที่มี จำกัด แล้วผ่านไปไม่กี่ของการจัดเรียงฟองสามารถดูแลที่ (เพียงเครื่องหมายวัตถุย้ายและย้ายไปข้างหน้าหรือถอยหลังในอาร์เรย์จนกว่าพวกเขาจะเรียงเพียงแค่ดูออกสำหรับวัตถุย้ายอื่น ๆ .
วงล้อประหลาด

คำตอบ:


14

การแบ่งพื้นที่เป็น O (N ^ 2) เสมอในกรณีที่เลวร้ายที่สุดและนั่นคือความซับซ้อนของสารสนเทศ

แต่มีขั้นตอนวิธีการที่ทำงานในเส้นเวลา O (N) พวกเขาทั้งหมดขึ้นอยู่กับสายการกวาดบางประเภท

โดยทั่วไปคุณจะต้องจัดเรียงวัตถุของคุณด้วยพิกัดเดียว สมมุติว่า X. ถ้าคุณเรียงลำดับทุกครั้งก่อนการตรวจจับการชนความซับซ้อนจะเป็น O (N * logN) เคล็ดลับคือการจัดเรียงเฉพาะเมื่อคุณเพิ่มวัตถุในฉากและต่อมาเมื่อมีบางสิ่งในฉากเปลี่ยนไป การเรียงลำดับหลังการเคลื่อนไหวนั้นไม่สำคัญ ดูกระดาษเชื่อมโยงด้านล่างสำหรับอัลกอริทึมที่ใช้ในการเคลื่อนไหวและยังคงทำงานในเวลาเชิงเส้น

จากนั้นคุณกวาดจากซ้ายไปขวา ทุกครั้งที่บรรทัดการกวาดของคุณข้ามจุดเริ่มต้นของวัตถุคุณวางไว้ในรายการชั่วคราว ทุกครั้งที่สายการกวาดของคุณออกจากวัตถุคุณจะนำมันออกจากรายการ คุณพิจารณาการชนภายในรายการชั่วคราวนี้เท่านั้น

เส้นกวาดไร้เดียงสาคือ O (N ^ 2) ในกรณีที่เลวร้ายที่สุดเช่นกัน (คุณทำให้วัตถุทั้งหมดขยายแผนที่ทั้งหมดจากซ้ายไปขวา) แต่คุณสามารถทำให้เป็น O (N) โดยทำให้มันฉลาดขึ้น (ดูลิงค์ด้านล่าง) อัลกอริทึมที่ดีจริงๆจะค่อนข้างซับซ้อน

นี่เป็นไดอะแกรมอย่างง่ายเกี่ยวกับการทำงานของสายการกวาด:

ขั้นตอนวิธีการกวาด

เส้นกวาดจากซ้ายไปขวา วัตถุจะถูกจัดเรียงตามพิกัด X

  • กรณีที่หนึ่ง: ตรวจสอบสองวัตถุแรก ไม่มีอะไรอื่นที่สำคัญ
  • กรณีที่สอง: วัตถุแรกถูกตรวจสอบและหายไปจากรายการ มีการตรวจสอบสองและสาม
  • กรณีที่สาม: แม้ว่าวัตถุนั้นจะชนกัน แต่เราไม่ได้ตรวจสอบ
  • กรณีที่สี่: เพราะเราตรวจสอบในกรณีนี้!

อัลกอริทึมเช่นนี้มีความซับซ้อน O (C * N) = O (N)

ที่มา: หลักสูตรเรขาคณิตสองปี

ในการตรวจจับการชนกันโดยทั่วไปเรียกว่าSweep and Pruneแต่ตระกูล algortithms ของ sweep line นั้นมีประโยชน์ในหลาย ๆ ด้าน

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


ตอนนี้ทราบว่านี้เป็นขั้นตอนวิธีการที่ดีที่สุดในทางทฤษฎี ไม่ได้หมายความว่ามันถูกใช้ ในทางปฏิบัติ O (N ^ 2) อัลกอริทึมที่มีการแบ่งพื้นที่จะมีความเร็วประสิทธิภาพที่ดีขึ้นในกรณีทั่วไป (ใกล้กับ O (N)) และความต้องการพิเศษบางอย่างสำหรับหน่วยความจำ นี่เป็นเพราะค่าคงที่ C ใน O (C * N) อาจสูงมาก! เนื่องจากเรามักจะมีหน่วยความจำเพียงพอและกรณีทั่วไปมีวัตถุที่แพร่กระจายอย่างสม่ำเสมอในพื้นที่ - อัลกอริทึมดังกล่าวจะทำงานได้ดีขึ้น แต่O (N) คือคำตอบของคำถามต้นฉบับ


box2d / bullet ใช้สิ่งนี้หรือไม่?
jokoon

3
"การกวาดและลูกพรุน" คือสิ่งที่ปกติเรียกว่าฟิสิกส์ สิ่งที่ดีคือคุณสามารถอัปเดตการเรียงลำดับได้เนื่องจากการจำลองขั้นสูง นอกจากนี้เส้นกวาดในกราฟฟิคของคุณนั้นค่อนข้างเล็กน้อยในแง่ของการใช้งาน (เหมาะสำหรับทฤษฎี) - คุณแค่ทำซ้ำในช่วงเริ่มต้น / สิ้นสุดดังนั้นคุณจะตรวจสอบการชนที่อาจเกิดขึ้นจริงเท่านั้น เห็นได้ว่าวิธีนี้ใช้ในการสร้างต้นไม้การแบ่งเชิงพื้นที่ที่มีความสามารถมากกว่าที่จะใช้โดยตรงเช่นกัน
Sean Middleditch

3
เนื่องจากในทางเทคนิคอาจมีการชนกันของ O (N ^ 2) เป็นคู่ดังนั้นจึงไม่เป็นความจริงเลยที่จะบอกว่าการกวาดและพรุนนั้นเป็น O (N) เสมอ แต่ความซับซ้อนหลักของอัลกอริทึมคือ O (N + c) โดยที่ c คือจำนวนการชนที่ค้นพบโดยอัลกอริทึม - มันไวต่อเอาท์พุตมากเท่าอัลกอริธึมฮัลล์นูน (ข้อมูลอ้างอิง: en.wikipedia.org/wiki/Output-sensitive_algorithm )
Steven Stadnicki

1
คุณควรคืนการอ้างสิทธิ์ของคุณด้วยสิ่งตีพิมพ์บางอย่างหรืออย่างน้อยชื่ออัลกอริทึม
sam hocevar

1
@ SamHocevar ฉันได้เพิ่มลิงก์ไปยังอัลกอริทึมการกวาดและลูกพรุนขั้นสูงจริงๆที่ทำงานในเวลาเชิงเส้นที่มีการแบ่งรายละเอียดของค่าคงที่ ความจริงที่ว่าอัลกอริทึมที่เรียกว่า "Sweep and Prune" เป็นสิ่งใหม่สำหรับฉันเนื่องจากฉันไม่เคยทำงานกับมันมาก่อน ฉันใช้อัลกอริธึมเหล่านี้ในการเลือกแผนที่ (ซึ่งเป็นการชนกัน 1 จุดกับวัตถุอื่น) ดังนั้นฉันจึงใช้ความรู้
MartinTeeVarga

8

ไม่การตรวจจับการชนกันไม่ใช่ O (N ^ 2) เสมอ

ตัวอย่างเช่นสมมติว่าเรามีช่องว่าง 100x100 กับวัตถุที่มีขนาด 10x10 เราสามารถแบ่งพื้นที่นี้ในเซลล์ 10x10 ด้วยกริด

แต่ละวัตถุสามารถอยู่ในเซลล์กริดได้สูงสุด 4 เซลล์ (มันอาจพอดีกับบล็อกหรือเป็นเซลล์ "ระหว่าง") เราสามารถเก็บรายการของวัตถุในแต่ละเซลล์

เราต้องตรวจสอบการชนในเซลล์เหล่านั้นเท่านั้น หากมีจำนวนสูงสุดของวัตถุต่อเซลล์กริด (พูดว่าไม่มีวัตถุมากกว่า 4 ในบล็อกเดียวกัน) จากนั้นตรวจจับการชนกันของแต่ละวัตถุคือ O (1) และตรวจจับการชนกันของวัตถุทั้งหมดคือ O (N)

นี่ไม่ใช่วิธีเดียวที่จะหลีกเลี่ยงความซับซ้อน O (N ^ 2) มีวิธีการอื่น ๆ ที่เพียงพอสำหรับกรณีการใช้งานอื่น ๆ - มักจะใช้โครงสร้างข้อมูลแบบต้นไม้

อัลกอริทึมที่ฉันอธิบายคือการแบ่งพาร์ติชันประเภทหนึ่งแต่มีอัลกอริทึมการแบ่งพื้นที่อื่น ดูประเภทของโครงสร้างข้อมูลการแบ่งพื้นที่สำหรับอัลกอริทึมเพิ่มเติมที่หลีกเลี่ยงความซับซ้อนทางโลก O (N ^ 2)

ทั้งกลไกการสนับสนุน Box2D และ Bullet เพื่อลดจำนวนคู่ที่ตรวจสอบ

จากคู่มือส่วน 4.15:

การประมวลผลการชนกันในขั้นตอนฟิสิกส์สามารถแบ่งออกเป็นเฟสแคบและกว้าง ในระยะแคบเราคำนวณจุดสัมผัสระหว่างคู่รูปร่าง ลองนึกภาพเรามีรูปร่าง N ด้วยการใช้กำลังดุร้ายเราจะต้องทำการเฟสแคบสำหรับคู่ N * N / 2

คลาส b2BroadPhase ลดภาระนี้โดยใช้ต้นไม้แบบไดนามิกสำหรับการจัดการคู่ สิ่งนี้จะลดจำนวนการเรียกเฟสแคบลงอย่างมาก

โดยปกติคุณจะไม่ต้องทำปฏิกิริยากับเฟสกว้างโดยตรง แต่ Box2D สร้างและจัดการเฟสกว้างภายใน นอกจากนี้ b2BroadPhase ได้รับการออกแบบโดยคำนึงถึงห่วงการจำลองของ Box2D ดังนั้นจึงไม่เหมาะสำหรับกรณีการใช้งานอื่น ๆ

จากBullet Wiki :

มีอัลกอริทึมแบบกระจายข้อความหลากหลายชนิดที่ปรับปรุงตามอัลกอริทึมไร้เดียงสา O (n ^ 2) ที่เพิ่งส่งกลับรายการคู่ที่สมบูรณ์ Broadphases ที่ได้รับการปรับให้เหมาะสมเหล่านี้บางครั้งแนะนำคู่ที่ไม่ได้มีการชนกันมากขึ้น แต่จะถูกชดเชยด้วยเวลาในการดำเนินการที่ดีขึ้น พวกเขามีลักษณะการทำงานที่แตกต่างกันและไม่มีใครมีประสิทธิภาพสูงกว่าคนอื่นในทุกสถานการณ์

ต้นไม้ AABB แบบไดนามิก

สิ่งนี้ถูกนำไปใช้โดย btDbvtBroadphase ใน Bullet

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

การกวาดและลูกพรุน (SAP)

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

ลิงค์ต่อไปนี้เป็นคำแนะนำทั่วไปเกี่ยวกับบรอดเฟสและคำอธิบายของอัลกอริธึมการกวาดและลูกพรุน (แม้ว่ามันจะเรียกมันว่า "การเรียงและการกวาด"):

http://www.ziggyware.com/readarticle.php?article_id=128

นอกจากนี้ให้ดูที่หน้าวิกิพีเดีย:

http://en.wikipedia.org/wiki/Sweep_and_prune


ลิงก์ไปยังคำถามที่คล้ายกันและแหล่งข้อมูลภายนอกจะทำให้คำตอบนี้เป็นคำตอบที่ดี
MichaelHouse

3
นี่เป็นสิ่งที่ผิด คุณยังคงได้ O (N ^ 2) มันจะเร็วกว่ามากเช่น N ^ 2/100 แต่ก็ยัง N ^ 2 เพื่อเป็นการพิสูจน์ให้พิจารณาว่าวัตถุทั้งหมดเกิดขึ้นในเซลล์เดียว
MartinTeeVarga

4
@ sm4 นี่เป็นกรณีที่เลวร้ายที่สุด O (N ^ 2) ซึ่งแน่นอนว่าจะเกิดอะไรขึ้นถ้าวัตถุทั้งหมดอยู่ในเซลล์เดียว อย่างไรก็ตามในเครื่องยนต์ฟิสิกส์วัตถุโดยทั่วไปจะไม่อยู่ในเซลล์เดียว ในตัวอย่างของฉันไม่มีวัตถุใดสามารถแบ่งเซลล์เดียวกันกับวัตถุอื่นได้มากกว่า 3 รายการ นี่จะเป็นสิ่งที่เกิดขึ้นในเอนจิ้นฟิสิกส์สำหรับวัตถุ "ปกติ" (และโดย "ปกติ" ฉันหมายถึง "ไม่ใช่แค่เซ็นเซอร์")
luiscubal

ฉันคิดว่าอัลกอริทึมของคุณจะต้องตรวจสอบใน 8 เซลล์รอบ ๆ ไม่ใช่แค่ 4 เซลล์
jokoon

6
@luiscubal Complexity มักจะเป็น "กรณีที่แย่ที่สุด" ในทางทฤษฎีคุณกำลังมองหา "รับประกัน" ความซับซ้อน เหมือนกันกับ quicksort ซึ่งก็คือ O (N ^ 2) และการผสานซึ่งก็คือ O (N * logN) Quicksort ทำงานได้ดีขึ้นกับข้อมูลจริงและมีข้อกำหนดด้านพื้นที่ว่างที่ต่ำกว่า แต่การรวมกันได้รับประกันความซับซ้อนที่ดีกว่า หากคุณต้องการพิสูจน์สิ่งที่ใช้ผสาน หากคุณต้องการเรียงลำดับบางสิ่งให้ใช้ quicksort
MartinTeeVarga

2

O (N ^ 2) หมายถึงความจริงที่ว่าถ้าคุณมีวัตถุ N ให้หาสิ่งที่ชนกับกรณีที่เลวร้ายที่สุดการคำนวณการชนกันของ N ^ 2 สมมติว่าคุณมีวัตถุ 3 ชิ้น ในการค้นหา "ผู้ที่กำลังกดปุ่มใคร" คุณต้องค้นหา:

o1 hitting o2?  o1 hitting o3?
o2 hitting o1?  o2 hitting o3?
o3 hitting o1?  o3 hitting o2?

นั่นคือการตรวจสอบ 6 ครั้งสำหรับการชนหรือการตรวจสอบ N * (N-1) ในการวิเคราะห์เชิงเส้นกำกับเราจะขยายพหุนามและค่าประมาณเป็น O (N ^ 2) ถ้าคุณมีวัตถุ 100 ชิ้นนั่นก็เท่ากับ 100 * 99 ซึ่งอยู่ใกล้พอที่ 100 * 100

ดังนั้นหากคุณแบ่งพื้นที่โดยใช้ octree จำนวนเฉลี่ยของการเปรียบเทียบระหว่างเนื้อความจะลดลง หากเป็นไปได้ที่วัตถุทั้งหมดจะรวมตัวกันในพื้นที่ขนาดเล็กมาก (พูดว่าถ้าคุณกำลังทำการจำลองการไหลของอนุภาคบางชนิดซึ่งอนุภาคสามารถรวมตัวกันในพื้นที่เดียวกัน) ดังนั้น O (N ^ 2) อาจยังคงอยู่ที่ คะแนนในการจำลอง (ซึ่งเป็นจุดที่คุณจะเห็นการชะลอตัว)

ดังนั้นจุดรวมของ O (N ^ 2) นั้นเป็นเพราะธรรมชาติของแต่ละศพที่ตรวจสอบร่างกายทุกส่วนในฉาก นั่นเป็นเพียงธรรมชาติของการคำนวณ หลายสิ่งหลายอย่างสามารถช่วยทำให้ราคาถูกลงได้ แม้แต่กราฟฉาก (พูดการตรวจจับระหว่างวัตถุในห้องเดียวกันเท่านั้น) จะลดจำนวนการคำนวณการชนที่จะทำอย่างมีนัยสำคัญ แต่มันจะยังคงเป็น O (M ^ 2) (โดยที่ M คือจำนวนวัตถุในห้อง ตรวจพบการชนกันของ ไดรฟ์ข้อมูลขอบเขตทรงกลมทำให้การตรวจสอบครั้งแรกเร็วมาก ( if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS) ดังนั้นแม้ว่าการตรวจจับการชนกันของข้อมูลจะเป็น O (N ^ 2) การคำนวณขอบเขตทรงกลมมีแนวโน้มที่จะเกิดขึ้นอย่างรวดเร็ว


ไม่จำเป็นต้องทำการตรวจสอบแรงเดรัจฉานเพื่อเป็นข้อมูลอ้างอิง: โดยไม่คำนึงถึงอัลกอริธึมที่ฉลาดวัตถุ N สามารถชนกันกับวัตถุอื่นทั้งหมดทำให้การชนกันของ O (N ^ 2) ที่ต้องการการประมวลผลงาน O (N ^ 2) อัลกอริทึมที่ดีสามารถทำได้ดีกว่าเมื่อมีการชนน้อยกว่า
Lorenzo Gatti
โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.