Có phải phát hiện va chạm luôn là O (n ^ 2) không?


14

Có phải động cơ vật lý có thể làm giảm sự phức tạp đó, ví dụ bằng cách nhóm các đối tượng ở gần nhau và kiểm tra va chạm trong nhóm này thay vì chống lại tất cả các đối tượng? (ví dụ, các vật thể ở xa có thể được loại bỏ khỏi một nhóm bằng cách nhìn vào vận tốc và khoảng cách của nó với các vật thể khác).

Nếu không, điều đó có làm cho va chạm tầm thường đối với các hình cầu (ở chế độ 3d) hoặc đĩa (trong 2d) không? Tôi nên tạo một vòng lặp kép, hoặc tạo một mảng các cặp thay thế?

EDIT: Đối với động cơ vật lý như đạn và box2d, phát hiện va chạm có còn O (N ^ 2) không?


12
Hai từ: Phân vùng không gian
MichaelHouse


1
Bạn đặt cược. Tôi tin rằng cả hai đều có triển khai SAP ( Sweep và Prune ) (trong số những người khác) là thuật toán O (n log (n)). Tìm kiếm "Phát hiện va chạm giai đoạn rộng" để tìm hiểu thêm.
MichaelHouse

2
@ Byte56 Sweep and Prune có độ phức tạp O (n log (n)) chỉ khi bạn cần sắp xếp mỗi khi bạn kiểm tra. Bạn muốn giữ một danh sách các đối tượng được sắp xếp và mỗi lần bạn thêm một đối tượng, chỉ cần sắp xếp nó vào đúng vị trí O (log (n)) do đó bạn nhận được O (log (n) + n) = O (n). Nó trở nên rất phức tạp khi các đối tượng bắt đầu di chuyển mặc dù!
MartinTeeVarga

1
@ sm4, nếu các chuyển động bị hạn chế thì một vài lần sắp xếp bong bóng có thể xử lý việc đó (chỉ cần đánh dấu các đối tượng đã di chuyển và di chuyển chúng tiến hoặc lùi trong mảng cho đến khi chúng được sắp xếp. Chỉ cần coi chừng các đối tượng di chuyển khác
quái vật ratchet

Câu trả lời:


14

Phân chia không gian luôn luôn là O (N ^ 2) trong trường hợp xấu nhất và đó là điều phức tạp trong tin học.

Tuy nhiên, có các thuật toán hoạt động trong thời gian tuyến tính O (N) . Tất cả chúng đều dựa trên một số loại đường quét.

Về cơ bản, bạn cần phải sắp xếp các đối tượng của mình theo một tọa độ. Giả sử X. Nếu bạn thực hiện sắp xếp mỗi lần trước khi phát hiện va chạm, độ phức tạp sẽ là O (N * logN). Mẹo nhỏ là chỉ sắp xếp khi bạn thêm đối tượng vào cảnh và sau đó khi có thứ gì đó trong cảnh thay đổi. Sắp xếp sau khi di chuyển không phải là nhỏ. Xem bài viết được liên kết dưới đây để biết thuật toán chuyển động và vẫn hoạt động trong thời gian tuyến tính.

Sau đó bạn quét từ trái sang phải. Mỗi khi đường quét của bạn vượt qua điểm bắt đầu của một đối tượng, bạn đặt nó vào danh sách tạm thời. Mỗi khi dòng quét của bạn thoát khỏi đối tượng, bạn lấy nó ra khỏi danh sách. Bạn xem xét va chạm chỉ trong danh sách tạm thời này.

Đường quét ngây thơ cũng là O (N ^ 2) trong trường hợp xấu nhất (bạn làm cho tất cả các đối tượng trải dài trên toàn bản đồ từ trái sang phải), nhưng bạn có thể làm cho O (N) bằng cách làm cho nó thông minh hơn (xem liên kết bên dưới). Một thuật toán thực sự tốt sẽ khá phức tạp.

Đây là sơ đồ đơn giản về cách hoạt động của dòng quét:

Thuật toán quét

Dòng quét từ trái sang phải. Các đối tượng được sắp xếp theo tọa độ X.

  • Trường hợp một: Hai đối tượng đầu tiên được kiểm tra. Không có gì khác quan trọng.
  • Trường hợp hai: Đối tượng đầu tiên đã được kiểm tra và bị loại khỏi danh sách. Hai và ba được kiểm tra.
  • Trường hợp thứ ba: Ngay cả khi đối tượng đó đang va chạm, chúng tôi không kiểm tra.
  • Trường hợp bốn: Bởi vì chúng tôi kiểm tra trong trường hợp này!

Các thuật toán như thế này có độ phức tạp O (C * N) = O (N).

Nguồn: Hai năm của các khóa học hình học tính toán.

Trong phát hiện va chạm, điều này thường được gọi là Sweep và Prune , nhưng dòng đại số của dòng đại số rất hữu ích trong nhiều lĩnh vực khác.

Đọc thêm khuyến nghị mà tôi tin là nằm ngoài phạm vi của câu hỏi này, nhưng vẫn rất thú vị: Các phương pháp quét và quét quy mô lớn hiệu quả với chèn và xóa AABB - Bài viết này trình bày thuật toán quét và quét nâng cao sử dụng các hộp giới hạn theo trục (AABB ) với việc sắp xếp có tính đến chuyển động. Algorig nhịp trình bày trong bài báo hoạt động trong thời gian tuyến tính.


Bây giờ lưu ý rằng đây là thuật toán tốt nhất trong lý thuyết . Nó không có nghĩa là nó được sử dụng. Trong thực tế, thuật toán O (N ^ 2) với phân chia không gian sẽ có tốc độ hiệu suất tốt hơn khôn ngoan trong trường hợp điển hình (gần với O (N)) và một số yêu cầu bổ sung cho bộ nhớ. Điều này là do hằng số C trong O (C * N) có thể rất cao! Vì chúng ta thường có đủ bộ nhớ và các trường hợp điển hình có các đối tượng trải đều trong không gian - thuật toán như vậy sẽ thực hiện TỐT HƠN. Nhưng O (N) là câu trả lời cho câu hỏi ban đầu.


box2d / đạn có sử dụng cái này không?
jokoon

3
"Quét và tỉa" là những gì thường được gọi là vật lý. Điều tuyệt vời là bạn có thể giữ cho việc sắp xếp được cập nhật khi mô phỏng được nâng cao. Ngoài ra, đường quét trong đồ họa của bạn hơi kém về mặt triển khai (tốt cho lý thuyết) - bạn sẽ chỉ lặp đi lặp lại trên hộp bắt đầu / kết thúc, vì vậy bạn chỉ kiểm tra các va chạm tiềm năng thực tế. Nhìn thấy phương pháp này được sử dụng để tạo ra các cây phân vùng không gian có khả năng hơn là sử dụng trực tiếp.
Sean Middleditch

3
Vì về mặt kỹ thuật thực sự có thể có các va chạm theo cặp O (N ^ 2), nên hoàn toàn không đúng khi nói rằng quét và cắt tỉa luôn luôn là O (N). Thay vào đó, độ phức tạp cốt lõi của thuật toán là O (N + c), trong đó c là số lượng va chạm được tìm thấy bởi thuật toán - nó nhạy với đầu ra , giống như nhiều thuật toán vỏ lồi. (Tham khảo: en.wikipedia.org/wiki/Output-sensitive_alacticm )
Steven Stadnicki

1
Bạn nên sao lưu khiếu nại của mình với một số ấn phẩm hoặc ít nhất là tên thuật toán.
sam hocevar

1
@SamHocevar Tôi đã thêm một liên kết đến thuật toán Sweep and Prune thực sự tiên tiến, hoạt động theo thời gian tuyến tính với sự cố chi tiết của các hằng số. Thực tế là các thuật toán được gọi là "Quét và cắt tỉa" là mới đối với tôi, vì tôi chưa bao giờ làm việc với nó. Tôi đã sử dụng các thuật toán này trong lựa chọn bản đồ (loại va chạm 1 điểm với các đối tượng khác), vì vậy tôi chỉ áp dụng kiến ​​thức.
MartinTeeVarga

8

Không. Phát hiện va chạm không phải lúc nào cũng là O (N ^ 2).

Chẳng hạn, giả sử chúng ta có một không gian 100x100 với các đối tượng có kích thước 10x10. Chúng ta có thể phân chia không gian này trong các ô của 10x10 bằng một lưới.

Mỗi đối tượng có thể nằm trong tối đa 4 ô lưới (nó có thể nằm vừa trong một khối hoặc nằm giữa các ô). Chúng ta có thể giữ một danh sách các đối tượng trong mỗi ô.

Chúng ta chỉ cần kiểm tra va chạm trong các ô đó. Nếu có số lượng đối tượng tối đa trên mỗi ô lưới (giả sử, không bao giờ có nhiều hơn 4 đối tượng trong cùng một khối), thì phát hiện va chạm cho mỗi đối tượng là O (1) và phát hiện va chạm cho tất cả các đối tượng là O (N).

Đây không phải là cách duy nhất để tránh sự phức tạp của O (N ^ 2). Có các phương pháp khác, đầy đủ hơn cho các trường hợp sử dụng khác - thường sử dụng cấu trúc dữ liệu dựa trên cây.

Thuật toán tôi mô tả là một loại phân vùng không gian , nhưng có các thuật toán phân vùng không gian khác. Xem Các loại cấu trúc dữ liệu phân vùng không gian để biết thêm một số thuật toán tránh sự phức tạp tạm thời O (N ^ 2).

Cả hai cơ chế hỗ trợ Box2D và Bullet để giảm số lượng cặp được kiểm tra.

Từ hướng dẫn , phần 4.15:

Xử lý va chạm trong một bước vật lý có thể được chia thành pha hẹp và pha rộng. Trong pha hẹp, chúng tôi tính toán các điểm tiếp xúc giữa các cặp hình. Hãy tưởng tượng chúng ta có N hình dạng. Sử dụng lực lượng vũ phu, chúng ta sẽ cần thực hiện pha hẹp cho các cặp N * N / 2.

Lớp b2BroadPhase giảm tải này bằng cách sử dụng cây động để quản lý cặp. Điều này làm giảm đáng kể số lượng các cuộc gọi pha hẹp.

Thông thường bạn không tương tác trực tiếp với pha rộng. Thay vào đó, Box2D tạo và quản lý một pha rộng trong nội bộ. Ngoài ra, b2BroadPhase được thiết kế với vòng lặp mô phỏng của Box2D, vì vậy nó có thể không phù hợp cho các trường hợp sử dụng khác.

Từ Bullet Wiki :

Có nhiều loại thuật toán broadphase cải thiện thuật toán O (n ^ 2) ngây thơ, chỉ trả về danh sách đầy đủ các cặp. Các dải tần được tối ưu hóa này đôi khi giới thiệu nhiều cặp không va chạm hơn nhưng điều này được bù đắp bởi thời gian thực hiện thường được cải thiện của chúng. Họ có đặc điểm hiệu suất khác nhau và không có gì vượt trội so với những người khác trong mọi tình huống.

Cây AABB động

Điều này được thực hiện bởi btDbvtBroadphase trong Bullet.

Như tên cho thấy, đây là một cây AABB động . Một tính năng hữu ích của broadphase này là cấu trúc thích ứng linh hoạt với các kích thước của thế giới và nội dung của nó. Nó được tối ưu hóa rất tốt và một broadphase có mục đích chung rất tốt. Nó xử lý các thế giới động nơi có nhiều đối tượng đang chuyển động, và việc thêm và xóa đối tượng nhanh hơn so với SAP.

Quét và tỉa (SAP)

Trong Bullet, đây là phạm vi các lớp của AxisSweep. Đây cũng là một broadphase có mục đích chung tốt, với một hạn chế là nó đòi hỏi một kích thước thế giới cố định, được biết trước. Broadphase này có hiệu suất tốt nhất cho các thế giới động lực điển hình, nơi hầu hết các đối tượng có ít hoặc không có chuyển động. Cả btAxisSweep3 và bt32AxisSweep3 định lượng điểm bắt đầu và điểm kết thúc cho mỗi trục dưới dạng số nguyên thay vì số dấu phẩy động, để cải thiện hiệu suất.

Liên kết sau đây là phần giới thiệu chung về broadphase và cũng là mô tả về thuật toán Sweep and Prune (mặc dù nó gọi là "Sắp xếp và quét"):

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

Ngoài ra, hãy xem trang wikipedia:

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


Một số liên kết đến các câu hỏi tương tự và các nguồn lực bên ngoài sẽ làm cho câu trả lời tuyệt vời này.
MichaelHouse

3
Cái này sai. Bạn vẫn nhận được O (N ^ 2). Nó sẽ nhanh hơn nhiều, đại loại như N ^ 2/100, nhưng vẫn là N ^ 2. Như một bằng chứng, chỉ cần xem xét rằng tất cả các đối tượng xảy ra trong một ô.
MartinTeeVarga

4
@ sm4 Đây là trường hợp xấu nhất O (N ^ 2), đây thực sự là điều xảy ra nếu tất cả các đối tượng nằm trong một ô. Tuy nhiên, trong một động cơ vật lý, các vật thể thường không nằm trong một ô. Trong ví dụ của tôi, không có đối tượng nào có thể chia sẻ cùng một ô với hơn 3 đối tượng khác. Đây sẽ là những gì xảy ra trong một động cơ vật lý cho các đối tượng "bình thường" (và theo "bình thường", ý tôi là "không chỉ là một cảm biến").
luiscubal

Tôi nghĩ rằng thuật toán của bạn sẽ yêu cầu kiểm tra 8 ô xung quanh, không chỉ 4 ô.
jokoon

6
@luiscubal Độ phức tạp luôn là "trường hợp xấu nhất". Về lý thuyết, bạn đang tìm kiếm sự phức tạp "được đảm bảo". Tương tự với quicksort, đó là O (N ^ 2) và mergesort, đó là O (N * logN). Quicksort thực hiện tốt hơn trên dữ liệu thực và có yêu cầu không gian thấp hơn. Nhưng sáp nhập đã đảm bảo sự phức tạp tốt hơn. Nếu bạn cần chứng minh điều gì đó, hãy sử dụng mergesort. Nếu bạn cần sắp xếp một cái gì đó, sử dụng quicksort.
MartinTeeVarga

2

O (N ^ 2) đề cập đến thực tế là nếu bạn có N đối tượng, hãy tìm ra những gì đang va chạm với những gì, trường hợp xấu nhất , tính toán va chạm N ^ 2. Nói rằng bạn có 3 đối tượng. Để tìm "ai đang đánh ai", bạn phải tìm:

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

Đó là 6 kiểm tra va chạm hoặc kiểm tra N * (N-1). Trong phân tích tiệm cận, chúng tôi sẽ mở rộng đa thức và gần đúng là O (N ^ 2). Nếu bạn có 100 đối tượng, thì đó sẽ là 100 * 99, gần đủ với 100 * 100.

Vì vậy, nếu bạn phân vùng không gian bằng cách sử dụng một octree chẳng hạn, số lượng so sánh trung bình giữa các cơ quan sẽ giảm. Nếu tất cả các đối tượng có thể tập hợp thành một khu vực rất nhỏ (giả sử nếu bạn đang thực hiện một loại mô phỏng dòng hạt nào đó, nơi các hạt có thể tập hợp trong cùng một khu vực) thì O (N ^ 2) vẫn có thể xảy ra tại các điểm trong mô phỏng (tại đó các điểm bạn sẽ thấy chậm lại).

Vì vậy, toàn bộ điểm của O (N ^ 2) là do bản chất của mỗi cơ thể kiểm tra mọi cơ thể khác trong cảnh. Đó chỉ là bản chất của tính toán. Rất nhiều thứ có thể giúp làm cho điều này rẻ hơn mặc dù. Ngay cả một biểu đồ cảnh (chỉ phát hiện giữa các đối tượng trong cùng một phòng ) sẽ làm giảm đáng kể số lần tính toán va chạm, nhưng vẫn sẽ là O (M ^ 2) (trong đó M là số lượng đối tượng trong phòng được phát hiện va chạm chống lại). Khối lượng giới hạn hình cầu làm cho kiểm tra ban đầu rất nhanh ( if( distance( myCenter, hisCenter ) > (myRadius+hisRadius) ) then MISS), vì vậy ngay cả khi phát hiện va chạm là O (N ^ 2), các tính toán hình cầu giới hạn có khả năng xảy ra rất nhanh.


Không cần phải kiểm tra lực lượng vũ phu làm tài liệu tham khảo: bất kể thuật toán thông minh, mỗi đối tượng N có thể va chạm với tất cả các đối tượng khác, tạo ra các va chạm O (N ^ 2) yêu cầu xử lý O (N ^ 2). Các thuật toán tốt chỉ có thể làm tốt hơn khi có ít va chạm.
Lorenzo Gatti
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.