Biorąc pod uwagę symetryczną rzeczywistą macierz , czy istnieje algorytm, który oblicza sumę ponad wszystkimi 1 \ leq i <j <k \ leq n ze złożonością czasową lepszą niż O (n ^ 3) ?
algorithms
time-complexity
użytkownik89217
źródło
źródło
Odpowiedzi:
Istnieje dość praktyczne podejście, które działa w czasie , gdzie jest liczbą bitów w słowie procesora. Główną ideą jest to, że iterujesz kolejno elementy macierzy w kolejności rosnącej (arbitralnie zrywaj wiązania) i „włączaj je”. Rozważ moment, w którym włączony jest największy element potrójnego . Dla uproszczenia załóżmy, że wspomniany element to . Naturalne jest dodanie wartości potrójnej do odpowiedzi teraz, gdy ostatni element jest włączony. Musimy więc policzyć liczbę możliwych , takich jak iO(n3/w) w aij,aik,ajk aij k aik ajk są już włączone (byłaby to liczba potrójnych, tutaj jest największym elementem, więc zostały całkowicie włączone). Tutaj możemy przyspieszyć naiwną implementację za pomocą optymalizacji bitów.aij O(n)
Szczegółowe informacje można znaleźć w następującej implementacji w C ++ 11, która powinna działać dla , (nie jest zbytnio zoptymalizowany, jednak nadal bije naiwne sumowanie dla o dużym marginesie przynajmniej na mojej maszynie).n⩽5000 |aij|⩽109 n=5000
Jeśli zastanawiasz się nad wykorzystaniem oszukiwania bitów, możesz użyć metody czterech Rosjan do tego samego wyniku, uzyskując algorytm , który powinien być mniej praktyczny (ponieważ jest dość duży na większości nowoczesnych urządzeń) ale teoretycznie jest lepszy. Rzeczywiście, wybierzmy i zachowajmy każdy wiersz macierzy jako tablicę liczb całkowitych od do , gdzie -ta liczba w tablica odpowiada bitom rzędu od włącznie do wyłączne wO(n3/logn) w b≈log2n ⌈nb⌉ 0 2b−1 i ib min(n,(i+1)b) 0 -indeksacja. Możemy wstępnie obliczyć iloczyn skalarny co dwa takie bloki w czasie . Aktualizacja pozycji w macierzy jest szybka, ponieważ zmieniamy tylko jedną liczbę całkowitą. Aby znaleźć iloczyn skalarny wierszy i po prostu iteruj po tablicach odpowiadających tym wierszom, wyszukaj produkty skalarne odpowiednich bloków w tabeli i podsumuj uzyskane produkty.O(22bb) i j
Powyższy akapit zakłada, że operacje na liczbach całkowitych zajmują czas . Jest to dość powszechne założenie , ponieważ zwykle nie zmienia w rzeczywistości szybkości porównawczej algorytmów (na przykład, jeśli nie użyjemy tego założenia, metoda brutalnej siły faktycznie działa w czasie (tutaj mierzymy czas w operacjach bitowych) jeśli weźmy wartości całkowite o wartościach bezwzględnych co najmniej do dla niektórych stałych (a w przeciwnym razie możemy rozwiązać problem z tak mnożenia macierzy), jednak sugerowana powyżej metoda czterech Rosjan używa⩽n O(1) O(n3logn) aij nε ε>0 O(nε) O(n3/logn) Operacje z numerami o rozmiarze w takim przypadku; więc wykonuje operacje bitowe , co jest nadal lepsze niż brutalna siła pomimo zmiany modelu).O(logn) O(n3)
Pytanie o istnienie podejścia jest jednak nadal interesujące.O(n3−ε)
Techniki (optymalizacja bitów i metoda czterech Rosjan) przedstawione w tej odpowiedzi nie są bynajmniej oryginalne i zostały tutaj przedstawione w celu uzupełnienia ekspozycji. Jednak znalezienie sposobu ich zastosowania nie było trywialne.
źródło
mat[i]
mat[j]
mat
które wydają się ważne. Rozumiem, jak można to zdefiniować, ale zastanawiam się, czy(mat[i] & mat[j]).count()
będzie działać zgodnie z oczekiwaniami z dowolnym kontenerem STL.mat
- myślę, że musimy użyćstd::vector<boost::dynamic_bitset<int64_t>>
.mat
: tak, miałem na myśli standardowy zestaw bitów, aleboost::dynamic_bitset
w tym przypadku jest jeszcze lepszy, ponieważ jego rozmiar nie musi być stały w czasie kompilacji. Przeredaguje odpowiedź, aby dodać ten szczegół i wyjaśnić podejście czterech Rosjan.