Saat memikirkan satu masalah, saya menyadari bahwa saya perlu membuat algoritma yang efisien untuk menyelesaikan tugas berikut:
Masalahnya: kita diberi kotak persegi dua dimensi dari sisi yang sisi-sisinya sejajar dengan sumbu. Kita bisa melihatnya dari atas. Namun, ada juga segmen horisontal. Setiap segmen memiliki bilangan bulat koordinat ( ) dan koordinat ( ) dan menghubungkan titik dan (lihat gambar di bawah).
Kami ingin tahu, untuk setiap segmen unit di bagian atas kotak, seberapa dalam kita dapat melihat secara vertikal di dalam kotak jika kita melihat melalui segmen ini.
Contoh: diberikan dan segmen yang terletak seperti pada gambar di bawah ini, hasilnya adalah (5, 5, 5, 3, 8, 3, 7, 8, 7) . Lihatlah seberapa dalam cahaya bisa masuk ke dalam kotak.m = 7 ( 5 , 5 , 5 , 3 , 8 , 3 , 7 , 8 , 7 )
Untungnya bagi kita, baik dan adalah cukup kecil dan kita dapat melakukan perhitungan off-line.
Algoritma termudah yang menyelesaikan masalah ini adalah brute-force: untuk setiap segmen melintasi seluruh array dan memperbaruinya jika perlu. Namun, itu memberi kita tidak terlalu mengesankan .
Peningkatan yang bagus adalah dengan menggunakan pohon segmen yang mampu memaksimalkan nilai pada segmen selama kueri dan membaca nilai akhir. Saya tidak akan menjelaskan lebih lanjut, tetapi kita melihat bahwa kompleksitas waktu adalah .
Namun, saya menghasilkan algoritma yang lebih cepat:
Garis besar:
Urutkan segmen dalam urutan menurun koordinat (waktu linier menggunakan variasi jenis penghitungan). Sekarang perhatikan bahwa jika setiap segmen -unit telah dicakup oleh segmen mana pun sebelumnya, tidak ada segmen berikut yang dapat mengikat berkas cahaya melalui segmen -unit ini lagi. Kemudian kita akan melakukan sapuan garis dari atas ke bawah kotak.x x
Sekarang mari kita perkenalkan beberapa definisi: segmen -unit adalah segmen horizontal imajiner pada sapuan yang koordinatnya bilangan bulat dan panjangnya adalah 1. Setiap segmen selama proses sapuan mungkin tidak ditandai (yaitu, berkas cahaya yang berasal dari bagian atas kotak dapat mencapai segmen ini) atau ditandai (huruf besar). Pertimbangkan segmen -unit dengan , selalu tanpa tanda. Mari kita juga memperkenalkan set . Setiap set akan berisi seluruh urutan segmen -unit bertanda yang ditandai (jika ada) dengan tanda berikut yang tidak ditandaix x x 1 = n x 2 = n + 1 S 0 = { 0 } , S 1 = { 1 } , ... , S n = { n } x segmen.
Kami membutuhkan struktur data yang dapat beroperasi pada segmen ini dan menetapkan secara efisien. Kami akan menggunakan struktur find-union yang diperluas oleh bidang yang memegang indeks segmen -unit maksimum (indeks segmen yang tidak ditandai ).
Sekarang kita dapat menangani segmen dengan efisien. Katakanlah kita sekarang mempertimbangkan segmen -th agar (menyebutnya "query"), yang dimulai di dan berakhir di . Kita perlu menemukan semua segmen -unit tak bertanda yang terdapat di dalam segmen ke- (ini persis segmen di mana berkas cahaya akan berakhir dengan caranya). Kami akan melakukan yang berikut: pertama, kami menemukan segmen tanpa tanda pertama di dalam kueri ( Temukan perwakilan dari set yang berisi dan dapatkan indeks maksimum dari set ini, yang merupakan segmen tanpa tanda menurut definisi ). Maka indeks inix 1 x 2 x i x 1 x y x x + 1 x ≥ x 2 ada di dalam kueri, tambahkan ke hasil (hasil untuk segmen ini adalah ) dan tandai indeks ini ( Kumpulan Union berisi dan ). Kemudian ulangi prosedur ini sampai kami menemukan semua segmen yang tidak ditandai , yaitu, selanjutnya Cari kueri memberi kami indeks .
Perhatikan bahwa setiap operasi pencarian-serikat kerja akan dilakukan hanya dalam dua kasus: apakah kita mulai mempertimbangkan segmen (yang dapat terjadi kali) atau kami baru saja menandai segmen unit (ini bisa terjadi kali). Dengan demikian kompleksitas keseluruhan adalah ( adalah fungsi Ackermann terbalik ). Jika ada sesuatu yang tidak jelas, saya bisa menguraikan lebih lanjut tentang ini. Mungkin saya akan dapat menambahkan beberapa gambar jika saya punya waktu.x n O ( ( n + m ) α ( n ) ) α
Sekarang saya mencapai "tembok". Saya tidak dapat menghasilkan algoritma linier, meskipun sepertinya harus ada satu. Jadi, saya punya dua pertanyaan:
- Apakah ada algoritma linear-waktu (yaitu, ) memecahkan masalah visibilitas segmen horizontal?
- Jika tidak, apa buktinya bahwa masalah visibilitas adalah ?