Saya memberi Anda daftar bitvektor dengan lebar . Tujuan Anda adalah mengembalikan dua vektor bit dari daftar yang tidak memiliki 1s sama, atau melaporkan bahwa tidak ada pasangan semacam itu.k
Misalnya, jika saya memberi Anda maka satu-satunya solusi adalah . Atau, input tidak memiliki solusi. Dan daftar apa pun yang berisi bitvector semua-nol dan elemen lain memiliki solusi sepele .{ 00110 , 11000 } [ 111 , 011 , 110 , 101 ] 000 ... 0 e { e , 000 ... 0 }
Berikut adalah contoh yang sedikit lebih sulit, tanpa solusi (setiap baris adalah vektor bit, kotak hitam adalah 1s dan kotak putih adalah 0s):
■ ■ ■ ■ □ □ □ □ □ □ □ □ □
■ □ □ □ ■ ■ ■ □ □ □ □ □ □
■ □ □ □ □ □ □ ■ ■ ■ □ □ □
■ □ □ □ □ □ □ □ □ □ ■ ■ ■
□ ■ □ □ □ ■ □ □ □ ■ ■ □ □
□ ■ □ □ ■ □ □ □ ■ □ □ □ ■
□ ■ □ □ □ □ ■ ■ □ □ □ ■ □ <-- All row pairs share a black square
□ □ ■ □ □ □ ■ □ ■ □ ■ □ □
□ □ ■ □ □ ■ □ ■ □ □ □ □ ■
□ □ ■ □ ■ □ □ □ □ ■ □ ■ □
□ □ □ ■ ■ □ □ ■ □ □ ■ □ □
□ □ □ ■ □ □ ■ □ □ ■ □ □ ■
□ □ □ ■ □ ■ □ □ ■ □ □ ■ □
Seberapa efisien dua bitvektor yang tidak tumpang tindih dapat ditemukan, atau ditunjukkan tidak ada?
Algoritma naif, di mana Anda hanya membandingkan setiap pasangan yang mungkin, adalah . Apakah mungkin melakukan lebih baik?
sumber
Jawaban:
Pemanasan: bitvektor acak
Sebagai pemanasan, kita bisa mulai dengan kasus di mana setiap bitvector dipilih secara seragam secara acak. Kemudian ternyata masalah tersebut dapat diselesaikan dalam waktu (lebih tepatnya, dapat diganti dengan ).O(n1.6min(k,lgn)) 1.6 lg3
Kami akan mempertimbangkan varian dua set masalah berikut:
Set diberikan dari bitvectors, menentukan di mana terdapat non-tumpang tindih pasangan .S,T⊆{0,1}k s∈S,t∈T
Teknik dasar untuk menyelesaikan ini adalah membagi-dan-taklukkan. Berikut ini adalah algoritma waktu menggunakan divide-and-conquer:O(n1.6k)
Split dan berdasarkan posisi bit pertama. Dengan kata lain, bentuk , , , .S T S0={s∈S:s0=0} S1={s∈S:s0=1} T0={t∈T:t0=0} T1={t∈T:t0=1}
Sekarang cari secara rekursif untuk pasangan yang tidak tumpang tindih dari , dari , dan dari . Jika ada panggilan rekursif menemukan pasangan yang tidak tumpang tindih, output itu, jika tidak output "Tidak ada pasangan yang tumpang tindih".S0,T0 S0,T1 T1,S0
Karena semua bitvektor dipilih secara acak, kita dapat mengharapkan dan . Dengan demikian, kami memiliki tiga panggilan rekursif, dan kami telah mengurangi ukuran masalah dengan faktor dua (kedua set ukurannya dikurangi dengan faktor dua). Setelah terpecah, salah satu dari dua set turun ke ukuran 1, dan masalahnya dapat diselesaikan dalam waktu linier. Kami mendapatkan relasi berulang di sepanjang garis , yang solusinya adalah . Akuntansi untuk menjalankan waktu lebih tepatnya dalam kasus dua set, kita melihat waktu berjalan adalah .|Sb|≈|S|/2 |Tb|≈|T|/2 lgmin(|S|,|T|) T(n)=3T(n/2)+O(nk) T(n)=O(n1.6k) O(min(|S|,|T|)0.6max(|S|,|T|)k)
Ini dapat ditingkatkan lebih lanjut, dengan mencatat bahwa jika , maka probabilitas bahwa pasangan yang tidak tumpang tindih ada secara eksponensial kecil. Secara khusus, jika adalah dua vektor acak, probabilitas bahwa mereka tidak tumpang tindih adalah . Jika , ada pasangan demikian, maka dengan ikatan gabungan, probabilitas ada pasangan yang tidak tumpang tindih adalah paling banyak . Ketika , ini adalah . Jadi, sebagai langkah pra-pemrosesan, jikak≥2.5lgn+100 x,y (3/4)k |S|=|T|=n n2 n2(3/4)k k≥2.5lgn+100 ≤1/2100 k≥2.5lgn+100 , maka kita dapat segera mengembalikan "Tidak ada pasangan yang tidak tumpang tindih" (probabilitas ini salah adalah sangat kecil), jika tidak kita jalankan algoritma di atas.
Dengan demikian kita mencapai waktu berjalan (atau untuk varian dua set yang diusulkan di atas), untuk kasus khusus di mana bitvektor dipilih secara seragam secara acak.O(n1.6min(k,lgn)) O(min(|S|,|T|)0.6max(|S|,|T|)min(k,lgn))
Tentu saja, ini bukan analisis kasus terburuk. Bitvektor acak jauh lebih mudah daripada kasus terburuk - tetapi mari kita perlakukan itu sebagai pemanasan, untuk mendapatkan beberapa ide yang mungkin bisa kita terapkan pada kasus umum.
Pelajaran dari pemanasan
Kita bisa belajar beberapa pelajaran dari pemanasan di atas. Pertama, bagi-dan-taklukkan (pemisahan pada posisi bit) tampaknya membantu. Kedua, Anda ingin membagi pada posisi bit dengan sebanyak mungkin dalam posisi itu; semakin banyak ada, semakin sedikit pengurangan dalam ukuran subproblem yang Anda dapatkan.1 0
Ketiga, ini menunjukkan bahwa masalahnya semakin sulit karena kepadatan semakin kecil - jika ada sangat sedikit di antara bitvectors (sebagian besar adalah 's), masalahnya terlihat cukup sulit, karena setiap split mengurangi ukuran subproblem sedikit. Jadi, tentukan densitas menjadi fraksi bit yang (yaitu, dari semua bit ), dan densitas posisi bit menjadi fraksi bitvektor yang pada posisi .1 1 0 Δ 1 nk i 1 i
Penanganan kepadatan sangat rendah
Sebagai langkah selanjutnya, kita mungkin bertanya-tanya apa yang terjadi jika kepadatannya sangat kecil. Ternyata jika kepadatan di setiap posisi bit lebih kecil dari , kami dijamin bahwa ada pasangan non-tumpang tindih: ada argumen keberadaan (non-konstruktif) yang menunjukkan bahwa beberapa non-tumpang tindih pasangan harus ada. Ini tidak membantu kami menemukannya, tetapi setidaknya kami tahu itu ada.1/k−−√
Mengapa demikian? Mari kita mengatakan bahwa sepasang bitvectors adalah ditutupi demi sedikit posisi jika . Perhatikan bahwa setiap pasangan bitvektor yang tumpang tindih harus dilindungi oleh beberapa posisi bit. Sekarang, jika kita memperbaiki posisi bit tertentu , jumlah pasangan yang dapat dicakup oleh posisi bit tersebut paling banyak . Menjumlahkan semua dari posisi bit, kami menemukan bahwa jumlah total pasangan yang dicakup oleh beberapa posisi bit adalahx,y i xi=yi=1 i (nΔ(i))2<n2/k k <n2 . Ini berarti harus ada beberapa pasangan yang tidak dicakup oleh posisi bit apa pun, yang menyiratkan bahwa pasangan ini tidak tumpang tindih. Jadi jika kepadatan cukup rendah di setiap posisi bit, maka pasangan yang tidak tumpang tindih pasti ada.
Namun, saya bingung untuk mengidentifikasi algoritma cepat untuk menemukan pasangan yang tidak tumpang tindih, dalam rezim ini, meskipun satu dijamin ada. Saya tidak segera melihat teknik yang akan menghasilkan waktu berjalan yang memiliki ketergantungan sub-kuadrat pada . Jadi, ini adalah kasus khusus yang bagus untuk difokuskan, jika Anda ingin meluangkan waktu memikirkan masalah ini.n
Menuju algoritma kasus umum
Dalam kasus umum, heuristik alami tampaknya adalah: memilih posisi bit dengan jumlah paling banyak (yaitu, dengan kepadatan tertinggi), dan membaginya. Dengan kata lain:i 1
Temukan posisi bit yang memaksimalkan .i Δ(i)
Split dan berdasarkan posisi bit . Dengan kata lain, bentuk , , , .S T i S0={s∈S:si=0} S1={s∈S:si=1} T0={t∈T:ti=0} T1={t∈T:ti=1}
Sekarang cari secara rekursif untuk pasangan yang tidak tumpang tindih dari , dari , dan dari . Jika ada panggilan rekursif menemukan pasangan yang tidak tumpang tindih, output itu, jika tidak output "Tidak ada pasangan yang tumpang tindih".S0,T0 S0,T1 T1,S0
Tantangannya adalah untuk menganalisis kinerjanya dalam kasus terburuk.
Mari kita asumsikan bahwa sebagai langkah pra-pemrosesan, pertama-tama kita menghitung kepadatan setiap posisi bit. Juga, jika untuk setiap , asumsikan bahwa langkah pra-pemrosesan menghasilkan "Pasangan yang tumpang tindih ada" (Saya menyadari bahwa ini tidak menunjukkan contoh pasangan yang tumpang tindih, tapi mari kita kesampingkan itu sebagai tantangan tersendiri). Semua ini dapat dilakukan dalam waktu . Informasi kepadatan dapat dipertahankan secara efisien karena kami melakukan panggilan rekursif; itu tidak akan menjadi kontributor dominan untuk waktu berjalan.Δ(i)<1/k−−√ i O(nk)
Apa yang akan menjadi waktu berjalan dari prosedur ini? Saya tidak yakin, tapi di sini ada beberapa pengamatan yang mungkin bisa membantu. Setiap tingkat rekursi mengurangi ukuran masalah sekitar bitvectors (mis., Dari bitvectors ke bitvectors). Oleh karena itu, rekursi hanya dapat mencapai kedalaman . Namun, saya tidak segera yakin bagaimana cara menghitung jumlah daun di pohon rekursi (ada banyak kurang dari daun), jadi saya tidak yakin berapa lama waktu berjalan ini seharusnya mengarah untuk.n/k−−√ n n−n/k−−√ k−−√ 3k√
sumber
Solusi lebih cepat saat , menggunakan perkalian matriksn≈k
Misalkan . Tujuan kami adalah melakukan lebih baik daripada waktu berjalan .n=k O(n2k)=O(n3)
Kita dapat menganggap bitvektor dan posisi bit sebagai node dalam grafik. Ada tepi antara node bitvector dan node posisi bit ketika bitvector memiliki 1 di posisi itu. Grafik yang dihasilkan adalah bipartit (dengan node yang mewakili bitvector di satu sisi dan node yang mewakili bitposition di sisi lain), dan memiliki node.n+k=2n
Dengan matriks adjacency dari sebuah grafik, kita dapat mengetahui apakah ada jalur dua hop antara dua simpul dengan mengkuadratkan dan memeriksa apakah matriks yang dihasilkan memiliki "tepi" antara dua simpul tersebut (yaitu entri tepi dalam matriks kuadrat tidak nol). Untuk tujuan kami, entri nol dalam matriks adjacency kuadrat sesuai dengan sepasang bitvektor yang tidak tumpang tindih (yaitu solusi). Kurangnya nol berarti tidak ada solusi.M M
Mengkuadratkan matriks nxn dapat dilakukan dalam waktu , di mana diketahui berada di bawah dan dikira .O(nω) ω 2.373 2
Jadi algoritmanya adalah:
Langkah paling mahal adalah mengkuadratkan adjacency matrix. Jika maka keseluruhan algoritma membutuhkan waktu , yang lebih baik daripada waktu naif .n=k O((n+k)ω)=O(nω) O(n3)
Solusi ini juga lebih cepat ketika tumbuh tidak terlalu banyak lebih lambat dan tidak terlalu banyak lebih cepat dari . Selama dan , maka lebih baik dari . Untuk yang diterjemahkan menjadi (asimtotik). Jika membatasi ke 2, maka batas melebar ke arah .k n k∈Ω(nω−2) k∈O(n2ω−1) (n+k)ω n2k w≈2.373 n0.731≤k≤n1.373 w nϵ≤k≤n2−ϵ
sumber
Ini setara dengan menemukan bit vektor yang merupakan bagian dari komplemen dari vektor lain; yaitu 1 nya hanya terjadi di mana 0's terjadi di yang lain.
Jika k (atau jumlah 1) kecil, Anda bisa mendapatkan waktu hanya dengan membuat semua himpunan bagian dari komplemen dari setiap bitvector dan menempatkannya dalam sebuah trie (menggunakan backtracking). Jika bitvector ditemukan dalam trie (kita dapat memeriksa masing-masing sebelum penyisipan komplemen-subset) maka kita memiliki pasangan yang tidak tumpang tindih.O(n2k)
Jika angka 1 atau 0 dibatasi ke angka yang bahkan lebih rendah dari k, maka eksponen dapat diganti dengan itu. Subset-indexing bisa pada setiap vektor atau komplemennya, selama probing menggunakan yang sebaliknya.
Ada juga skema untuk superset-menemukan dalam sebuah trie yang hanya menyimpan masing-masing vektor hanya sekali, tetapi tidak melewatkan selama penyelidikan untuk apa yang saya percaya adalah kompleksitas agregat yang sama; yaitu ia memiliki penyisipan tetapi pencarian .o(k) o(2k)
sumber
Mewakili vektor bit sebagai matriks . Ambil dan antara 1 dan .n×k M i j n
Kompleksitas
Menggunakan perkalian naif, ini membutuhkan operasi aritmatika . Jika , dibutuhkan operasi menggunakan algoritma Coppersmith-Winograd yang sama sekali tidak praktis, atau menggunakan algoritma Strassen. Jika , maka masalahnya dapat diselesaikan menggunakan operasi .O(n2k) n=k O(n2.37) O(n2.8) k=O(n0.302) n2+o(1)
sumber