Tìm một cặp vectơ bit không chồng chéo


17

Tôi cung cấp cho bạn một danh sách bitvector chiều rộng . Mục tiêu của bạn là trả về hai bitvector từ danh sách không có điểm chung 1 hoặc nếu không sẽ báo cáo rằng không có cặp nào như vậy tồn tại.nk

Ví dụ: nếu tôi đưa cho bạn thì giải pháp duy nhất là . Ngoài ra, đầu vào không có giải pháp. Và bất kỳ danh sách nào chứa bitvector hoàn toàn bằng không và một phần tử khác có một giải pháp tầm thường .[00110,01100,11000]{00110,11000}[111,011,110,101]000...0e{e,000...0}

Đây là một ví dụ khó hơn một chút, không có giải pháp (mỗi hàng là một vectơ bit, hình vuông màu đen là 1s và hình vuông màu trắng là 0s):

■ ■ ■ ■ □ □ □ □ □ □ □ □ □
■ □ □ □ ■ ■ ■ □ □ □ □ □ □ 
■ □ □ □ □ □ □ ■ ■ ■ □ □ □
■ □ □ □ □ □ □ □ □ □ ■ ■ ■
□ ■ □ □ □ ■ □ □ □ ■ ■ □ □
□ ■ □ □ ■ □ □ □ ■ □ □ □ ■
□ ■ □ □ □ □ ■ ■ □ □ □ ■ □ <-- All row pairs share a black square
□ □ ■ □ □ □ ■ □ ■ □ ■ □ □
□ □ ■ □ □ ■ □ ■ □ □ □ □ ■
□ □ ■ □ ■ □ □ □ □ ■ □ ■ □
□ □ □ ■ ■ □ □ ■ □ □ ■ □ □
□ □ □ ■ □ □ ■ □ □ ■ □ □ ■
□ □ □ ■ □ ■ □ □ ■ □ □ ■ □

Làm thế nào hiệu quả có thể tìm thấy hai bitvector không chồng chéo, hoặc được hiển thị không tồn tại?

Thuật toán ngây thơ, trong đó bạn chỉ cần so sánh mọi cặp có thể, là . Có thể làm tốt hơn?O(n2k)


Giảm khả năng: Bạn có một đồ thị với một đỉnh cho mỗi vectơ và cạnh giữa hai đỉnh nếu hai vectơ tương ứng có 1 điểm chung. Bạn muốn biết đường kính đồ thị là . Nhưng có vẻ khó đi nhanh hơn . G2O(n2k)
François

@ FrançoisGodi Bất kỳ thành phần đồ thị được kết nối nào có ba nút và cạnh bị thiếu có đường kính ít nhất hai. Với một đại diện danh sách kề, phải mất thời gian để kiểm tra điều đó. O(V)
Craig Gidney

@Strilanc Chắc chắn, nếu không có giải pháp nào thì đồ thị đã hoàn thành (rõ ràng hơn đường kính = 1, bạn đã đúng), nhưng việc tính toán biểu diễn danh sách kề có thể dài.
François

Là nhỏ hơn chiều rộng từ của máy của bạn? k
Raphael

1
@TomvanderZanden Nghe có vẻ như nó sẽ vi phạm các bất biến mà cấu trúc dữ liệu có thể dựa vào. Đặc biệt, sự bình đẳng đó nên mang tính bắc cầu. Tôi đã suy nghĩ về việc sử dụng một bộ ba và tôi không biết làm thế nào để tránh một cú đánh 2 nhân mỗi khi truy vấn bitmask có 0.
Craig Gidney

Câu trả lời:


10

Khởi động: bitvector ngẫu nhiên

Khi khởi động, chúng ta có thể bắt đầu với trường hợp mỗi bitvector được chọn iid một cách ngẫu nhiên. Sau đó, hóa ra vấn đề có thể được giải quyết trong thời gian (chính xác hơn, có thể được thay thế bằng ).O(n1.6min(k,lgn))lg 31.6lg3

Chúng tôi sẽ xem xét biến thể hai bộ sau đây của vấn đề:

Bộ cho của bitvectors, xác định nơi tồn tại một không chồng chéo cặp . s S , t TS,T{0,1}ksS,tT

Kỹ thuật cơ bản để giải quyết điều này là phân chia và chinh phục. Dưới đây là thuật toán thời gian bằng cách sử dụng phép chia và chinh phục:O(n1.6k)

  1. Tách và dựa trên vị trí bit đầu tiên. Nói cách khác, biểu mẫu , , , .T S 0 = { s S : s 0 = 0 } S 1 = { s S : s 0 = 1 } T 0 = { t T : t 0 = 0 } T 1 = { t T : t 0 = 1 }STS0={sS:s0=0}S1={sS:s0=1}T0={tT:t0=0}T1={tT:t0=1}

  2. Bây giờ, hãy tìm đệ quy một cặp không chồng chéo từ , từ và từ . Nếu bất kỳ cuộc gọi đệ quy nào tìm thấy một cặp không chồng lấp, hãy xuất nó, nếu không thì xuất ra "Không tồn tại cặp chồng chéo".S 0 , T 1 T 1 , S 0S0,T0S0,T1T1,S0

Vì tất cả các bitvector được chọn ngẫu nhiên, chúng ta có thể mong đợi và . Do đó, chúng tôi có ba cuộc gọi đệ quy và chúng tôi đã giảm kích thước của vấn đề xuống hai lần (cả hai bộ đều giảm kích thước theo hệ số hai). Sau khi chia tách , một trong hai bộ giảm xuống kích thước 1 và vấn đề có thể được giải quyết trong thời gian tuyến tính. Chúng ta có một mối quan hệ lặp lại dọc theo các dòng , có giải pháp là . Kế toán thời gian chạy chính xác hơn trong trường hợp hai bộ, chúng ta thấy thời gian chạy là .| T b | | T | / 2 lg phút ( | S | , | T | ) T ( n ) = 3 T ( n / 2 ) + O ( n k ) T ( n ) = O ( n 1.6 k ) O|Sb||S|/2|Tb||T|/2lgmin(|S|,|T|)T(n)=3T(n/2)+O(nk)T(n)=O(n1.6k)O(min(|S|,|T|)0.6max(|S|,|T|)k)

Điều này có thể được cải thiện hơn nữa, bằng cách lưu ý rằng nếu , thì xác suất tồn tại một cặp không chồng chéo là nhỏ theo cấp số nhân. Cụ thể, nếu là hai vectơ ngẫu nhiên, xác suất chúng không trùng nhau là . Nếu , có cặp như vậy, do liên kết ràng buộc, xác suất tồn tại một cặp không chồng chéo là tối đa . Khi , đây là . Vì vậy, là bước tiền xử lý, nếux , y ( 3 / 4 ) k | S | = | T | = N n 2 n 2 ( 3 / 4 ) k k 2,5 lg n + 100 1 / 2 100 k 2,5 lg n + 100k2.5lgn+100x,y(3/4)k|S|=|T|=nn2n2(3/4)kk2.5lgn+1001/2100k2.5lgn+100, sau đó chúng ta có thể trả về ngay lập tức "Không tồn tại cặp không chồng chéo" (xác suất này không chính xác là nhỏ không đáng kể), nếu không chúng ta chạy thuật toán trên.

Do đó, chúng tôi đạt được thời gian chạy của (hoặc cho biến thể hai bộ được đề xuất ở trên), trong trường hợp đặc biệt trong đó các bitvector được chọn thống nhất một cách ngẫu nhiên.O ( tối thiểu ( | S | , | T | ) 0.6 max ( | S | , | T | ) min ( k , lg n ) )O(n1.6min(k,lgn))O(min(|S|,|T|)0.6max(|S|,|T|)min(k,lgn))

Tất nhiên, đây không phải là một phân tích trường hợp xấu nhất. Bitvector ngẫu nhiên dễ dàng hơn đáng kể so với trường hợp xấu nhất - nhưng hãy coi nó như một sự khởi động, để có được một số ý tưởng mà có lẽ chúng ta có thể áp dụng cho trường hợp chung.

Bài học từ sự khởi động

Chúng ta có thể học được một vài bài học từ sự khởi động ở trên. Đầu tiên, phân chia và chinh phục (tách trên một vị trí bit) có vẻ hữu ích. Thứ hai, bạn muốn phân chia trên một vị trí bit với càng nhiều ở vị trí đó càng tốt; Càng có nhiều , kích thước của bài toán con bạn giảm càng ít.010

Thứ ba, điều này cho thấy vấn đề trở nên khó khăn hơn khi mật độ của trở nên nhỏ hơn - nếu có rất ít trong số các bitvector (chúng chủ yếu là ), vấn đề có vẻ khá khó khăn, vì mỗi lần phân tách giảm kích thước của các bài toán con một chút. Vì vậy, xác định mật độ là phân số của các bit là (nghĩa là trong số tất cả các bit ) và mật độ của vị trí bit là phân số của bitvector là tại vị trí .1 0 Δ 1 n k i 1 i110Δ1nki1i

Xử lý mật độ rất thấp

Bước tiếp theo, chúng ta có thể tự hỏi điều gì sẽ xảy ra nếu mật độ cực kỳ nhỏ. Nó chỉ ra rằng nếu mật độ ở mọi vị trí bit nhỏ hơn , chúng tôi đảm bảo rằng tồn tại một cặp không chồng chéo: có một đối số tồn tại (không mang tính xây dựng) cho thấy một số không chồng lấp cặp phải tồn tại. Điều này không giúp chúng tôi tìm thấy nó, nhưng ít nhất chúng tôi biết nó tồn tại.1/k

Tại sao điều này là trường hợp? Giả sử rằng một cặp bitvector được bao phủ bởi vị trí bit nếu . Lưu ý rằng mỗi cặp bitvector chồng chéo phải được bao phủ bởi một số vị trí bit. Bây giờ, nếu chúng ta sửa một vị trí bit cụ thể , số lượng cặp có thể được bao phủ bởi vị trí bit đó nhiều nhất là . Tổng hợp trên tất cả của các vị trí bit, chúng tôi thấy rằng tổng số cặp được bao phủ bởi một số vị trí bit lài x i = y i = 1 i ( n Δ ( i ) ) 2 < n 2 / k k < n 2x,yixi=yi=1i(nΔ(i))2<n2/kk<n2. Điều này có nghĩa là phải tồn tại một số cặp không được bao phủ bởi bất kỳ vị trí bit nào, điều này ngụ ý rằng cặp này không chồng chéo. Vì vậy, nếu mật độ đủ thấp ở mọi vị trí bit, thì một cặp không chồng chéo chắc chắn tồn tại.

Tuy nhiên, tôi không thể xác định được một thuật toán nhanh để tìm ra một cặp không chồng chéo như vậy, trong các chế độ này, mặc dù một thuật toán được đảm bảo tồn tại. Tôi không thấy ngay bất kỳ kỹ thuật nào mang lại thời gian chạy có sự phụ thuộc bậc hai vào . Vì vậy, đây là một trường hợp đặc biệt tốt đẹp để tập trung vào, nếu bạn muốn dành thời gian suy nghĩ về vấn đề này.n

Hướng tới một thuật toán trường hợp chung

Trong trường hợp chung, một heuristic tự nhiên dường như là: chọn vị trí bit với số lượng nhiều nhất là (nghĩa là có mật độ cao nhất) và phân chia trên đó. Nói cách khác:1i1

  1. Tìm vị trí bit tối đa hóa .Δ ( i )iΔ(i)

  2. Tách và dựa trên vị trí bit . Nói cách khác, biểu mẫu , , , .T i S 0 = { s S : s i = 0 } S 1 = { s S : s i = 1 } T 0 = { t T : t i = 0 } T 1 = { t T : t i = 1 }STiS0={sS:si=0}S1={sS:si=1}T0={tT:ti=0}T1={tT:ti=1}

  3. Bây giờ, hãy tìm đệ quy một cặp không chồng chéo từ , từ và từ . Nếu bất kỳ cuộc gọi đệ quy nào tìm thấy một cặp không chồng lấp, hãy xuất nó, nếu không thì xuất ra "Không tồn tại cặp chồng chéo".S 0 , T 1 T 1 , S 0S0,T0S0,T1T1,S0

Thách thức là phân tích hiệu suất của nó trong trường hợp xấu nhất.

Chúng ta hãy giả sử rằng là một bước tiền xử lý, trước tiên chúng ta tính mật độ của mọi vị trí bit. Ngoài ra, nếu cho mọi , giả sử rằng bước tiền xử lý xuất ra "Một cặp chồng chéo tồn tại" (tôi nhận ra rằng điều này không thể hiện ví dụ về một cặp chồng chéo, nhưng hãy đặt nó sang một bên như một thách thức riêng biệt). Tất cả điều này có thể được thực hiện trong thời gian . Thông tin mật độ có thể được duy trì hiệu quả khi chúng tôi thực hiện các cuộc gọi đệ quy; nó sẽ không phải là người đóng góp chi phối thời gian hoạt động. iO(nk)Δ(i)<1/kiO(nk)

Thời gian chạy của thủ tục này sẽ là gì? Tôi không chắc chắn, nhưng đây là một vài quan sát có thể giúp ích. Mỗi cấp độ đệ quy làm giảm kích thước bài toán khoảng bitvector (ví dụ: từ bitvector đến bitvector). Do đó, đệ quy chỉ có thể đi sâu về các mức . Tuy nhiên, tôi không chắc chắn làm thế nào để đếm số lượng lá trong cây đệ quy (có rất ít hơn lá), vì vậy tôi không chắc thời gian chạy này sẽ dẫn đến thời gian nào đến. nn-n/n/knnn/k 3k3k


mật độ quảng cáo thấp: đây có vẻ là một loại đối số lỗ chim bồ câu. Có lẽ nếu chúng tôi sử dụng ý tưởng chung của bạn (chia cột với nhiều người nhất), chúng tôi sẽ nhận được giới hạn tốt hơn vì trường hợp (chúng tôi không tái diễn) đã loại bỏ "hầu hết"? (S1,T1)
Raphael

Tổng số người có thể là một tham số hữu ích. Bạn đã chỉ ra một giới hạn thấp hơn mà chúng ta có thể sử dụng để chặt cây; chúng ta cũng có thể hiển thị giới hạn trên? Ví dụ: nếu có nhiều hơn , chúng ta có ít nhất trùng nhau. cckc
Raphael

Nhân tiện, làm thế nào để bạn đề xuất chúng tôi thực hiện phân chia đầu tiên; tùy tiện? Tại sao không chỉ tách toàn bộ đầu vào wrt một số cột ? Chúng ta chỉ cần lặp lại trong -case (không có giải pháp nào trong số những người chia sẻ một tại ). Trong kỳ vọng, điều đó cho qua một ràng buộc của (nếu cố định). Đối với một ràng buộc chung, bạn đã chỉ ra rằng chúng ta có thể (giả sử mức giới hạn dưới mà bạn đề xuất) rằng chúng ta loại bỏ ít nhất với mỗi phần tách, dường như ngụ ý một trường hợp xấu nhất ràng buộc. Hay tôi đang thiếu một cái gì đó? i0iT(n)=T(n/2)+O(nk)O(nk)kn/kO(nk)
Raphael

À, điều đó là sai, tất nhiên, vì nó không xem xét sự không phù hợp 0-1. Đó là những gì tôi nhận được khi cố gắng suy nghĩ trước khi ăn sáng, tôi đoán vậy.
Raphael

@Raphael, có hai vấn đề: (a) các vectơ có thể chủ yếu là số không, vì vậy bạn không thể tin vào việc chia 50-50; sự tái phát sẽ là một cái gì đó giống như , (b) quan trọng hơn, nó không đủ để chỉ tái diễn trên tập hợp con 0; bạn cũng cần kiểm tra các cặp giữa một vectơ từ tập con 0 và vectơ từ tập con 1, do đó, có một đệ quy bổ sung hoặc hai để làm. (Tôi nghĩ sao? Tôi hy vọng tôi hiểu đúng.)T(n)=T((nn/k)k)+O(nk)
DW

8

Giải pháp nhanh hơn khi , sử dụng phép nhân ma trậnnk

Giả sử . Mục tiêu của chúng tôi là làm tốt hơn thời gian chạy .n=kO(n2k)=O(n3)

Chúng ta có thể nghĩ về các bitvector và vị trí bit như các nút trong biểu đồ. Có một cạnh giữa một nút bitvector và một nút vị trí bit khi bitvector có 1 ở vị trí đó. Biểu đồ kết quả là bipartite (với các nút đại diện cho bitvector ở một bên và các nút đại diện cho bitpose ở phía bên kia) và có các nút .n+k=2n

Dựa vào ma trận kề của đồ thị, chúng ta có thể biết liệu có một đường hai bước giữa hai đỉnh bằng cách bình phương hay không và kiểm tra xem ma trận kết quả có "cạnh" giữa hai đỉnh đó hay không (nghĩa là lối vào của cạnh trong ma trận bình phương là khác không). Đối với mục đích của chúng tôi, một mục nhập số 0 trong ma trận kề bình phương tương ứng với một cặp bitvector không chồng chéo (nghĩa là một giải pháp). Việc thiếu bất kỳ số 0 nào có nghĩa là không có giải pháp.M M

Bình phương một ma trận nxn có thể được thực hiện trong thời gian , trong đó được biết là dưới và được phỏng đoán là .O(nω)ω2.3732

Vậy thuật toán là:

  • Chuyển đổi các bitvector và vị trí bit thành một đồ thị lưỡng cực với các nút và nhiều nhất là các cạnh . Điều này mất thời gian .n+knkO(nk)
  • Tính ma trận kề của đồ thị. Điều này làm mất thời gian và không gian .O((n+k)2)
  • Bình phương ma trận kề. Điều này làm mất thời gian .O((n+k)ω)
  • Tìm kiếm phần bitvector của ma trận kề cho các mục không. Điều này mất thời gian .O(n2)

Bước đắt nhất là bình phương ma trận kề. Nếu thì thuật toán tổng thể mất thời gian , tốt hơn thời gian ngây thơ .n=kO((n+k)ω)=O(nω)O(n3)

Giải pháp này cũng nhanh hơn khi phát triển không quá nhiều - chậm hơn và không quá nhanh hơn . Miễn là và , thì là tốt hơn hơn . Đối với có nghĩa là (không có triệu chứng). Nếu giới hạn ở 2, thì giới hạn sẽ mở rộng về phía .knkΩ(nω2)kO(n2ω1)(n+k)ωn2kw2.373n0.731kn1.373wnϵkn2ϵ


1. Điều này cũng tốt hơn giải pháp ngây thơ nếu nhưng . 2. Nếu , một heuristic có thể là: chọn một tập hợp con ngẫu nhiên của các vị trí bit, giới hạn ở các vị trí bit đó và sử dụng phép nhân ma trận để liệt kê tất cả các cặp không trùng nhau trong các vị trí bit đó; đối với mỗi cặp như vậy, kiểm tra xem nó có giải quyết được vấn đề ban đầu không. Nếu không có nhiều cặp không trùng nhau ở các vị trí bit đó, thì điều này cung cấp một tốc độ vượt qua thuật toán ngây thơ. Tuy nhiên tôi không biết giới hạn trên tốt về số lượng các cặp như vậy. k=Ω(n)k=o(n1.457)knnnn
DW

4

Điều này tương đương với việc tìm một vectơ bit là tập con của phần bù của vectơ khác; tức là 1 của nó chỉ xảy ra khi 0 là khác.

Nếu k (hoặc số 1) nhỏ, bạn có thể nhận được thời gian bằng cách tạo tất cả các tập hợp con của phần bù của mỗi bitvector và đặt chúng vào một trie (sử dụng quay lui). Nếu một bitvector được tìm thấy trong bộ ba (chúng ta có thể kiểm tra từng cái trước khi chèn tập hợp con bổ sung) thì chúng ta có một cặp không chồng chéo.O(n2k)

Nếu số 1 hoặc 0 được giới hạn ở số thậm chí thấp hơn k, thì số mũ có thể được thay thế bằng số đó. Việc lập chỉ mục tập hợp con có thể nằm trên mỗi vectơ hoặc phần bù của nó, miễn là việc thăm dò sử dụng ngược lại.

Ngoài ra còn có một kế hoạch tìm siêu âm trong một bộ ba chỉ lưu trữ mỗi vectơ chỉ một lần, nhưng bỏ qua bit trong các thăm dò cho những gì tôi tin là độ phức tạp tổng hợp tương tự; tức là nó có chèn nhưng tìm kiếm.o(k)o(2k)


cảm ơn. Độ phức tạp của giải pháp của bạn là , trong đó là xác suất 1 giây trong bitvector. Một vài chi tiết triển khai: mặc dù đây là một cải tiến nhỏ, nhưng không cần phải tính toán và lưu trữ các bổ sung trong bộ ba. Chỉ cần làm theo các nhánh bổ sung khi kiểm tra một trận đấu không chồng chéo là đủ. Và, lấy số 0 trực tiếp làm ký tự đại diện, cũng không cần ký tự đại diện đặc biệt. n2(1p)kp
Mauro Lacy

2

Đại diện các vectơ bit như là một ma trận . Lấy và trong khoảng từ 1 đến .n×kMijn

(MMT)ij=lMilMjl.

(MMT)ij , sản phẩm chấm của vectơ thứ và thứ , khác không nếu và chỉ khi vectơ và chia sẻ chung 1. Vì vậy, để tìm một giải pháp, hãy tính và trả về vị trí của mục nhập số 0, nếu mục đó tồn tại.ijijMMT

Phức tạp

Sử dụng phép nhân ngây thơ, điều này đòi hỏi các phép toán số học . Nếu , phải thực hiện các thao tác bằng thuật toán Coppersmith-Winograd hoàn toàn không thực tế hoặc bằng thuật toán Strassen. Nếu , thì vấn đề có thể được giải quyết bằng các thao tác .n = k O ( n 2.37 ) O ( n 2.8 ) k = O ( n 0.302 ) n 2 + o ( 1 )O(n2k)n=kO(n2.37)O(n2.8)k=O(n0.302)n2+o(1)


Điều này khác với câu trả lời của Strilanc như thế nào?
DW

1
@DW Sử dụng ma trận -by- thay vì ma trận -by- là một sự cải tiến. Ngoài ra, nó đề cập đến một cách để cắt bỏ yếu tố k khi k << n, vì vậy điều đó có thể hữu ích. k ( n + k ) ( n + k )nk(n+k)(n+k)
Craig Gidney 21/07/2015
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.