Combinatorics memainkan peran penting dalam ilmu komputer. Kami sering menggunakan metode kombinatorial baik dalam analisis maupun desain dalam algoritma. Misalnya satu metode untuk menemukan penutup -vertex yang diatur dalam grafik mungkin hanya memeriksa semua \ binom {n} {k} subset yang mungkin. Sementara fungsi binomial tumbuh secara eksponensial, jika k adalah konstanta tetap kita berakhir dengan algoritma waktu polinomial dengan analisis asimptotik.( n k
Sering kali masalah kehidupan nyata membutuhkan mekanisme kombinatorial yang lebih kompleks yang dapat kita definisikan dalam hal kekambuhan. Salah satu contoh terkenal adalah deret fibonacci (naif) didefinisikan sebagai:
Sekarang menghitung nilai suku ke- tumbuh secara eksponensial menggunakan pengulangan ini, tetapi berkat pemrograman dinamis, kita dapat menghitungnya dalam waktu linier. Sekarang, tidak semua perulangan meminjamkan diri ke DP (begitu saja, fungsi faktorial), tetapi itu adalah properti yang berpotensi dapat dieksploitasi ketika mendefinisikan beberapa hitungan sebagai perulangan daripada fungsi pembangkit.
Menghasilkan fungsi adalah cara yang elegan untuk memformalkan beberapa hitungan untuk struktur yang diberikan. Mungkin yang paling terkenal adalah fungsi pembangkit binomial yang didefinisikan sebagai:
Untungnya ini memiliki solusi bentuk tertutup. Tidak semua fungsi yang menghasilkan mengizinkan deskripsi yang ringkas.
Sekarang pertanyaan saya adalah ini: seberapa sering menghasilkan fungsi yang digunakan dalam desain algoritma? Sangat mudah untuk melihat bagaimana mereka dapat dieksploitasi untuk memahami tingkat pertumbuhan yang dibutuhkan oleh suatu algoritma melalui analisis, tetapi apa yang bisa mereka katakan kepada kami tentang masalah ketika membuat metode untuk memecahkan beberapa masalah?
Jika berkali-kali jumlah yang sama dapat diformulasi ulang sebagai perulangan, maka ia dapat digunakan untuk pemrograman dinamis, tetapi sekali lagi mungkin fungsi pembangkit yang sama memiliki bentuk tertutup. Jadi tidak dipotong secara merata.
sumber
Jawaban:
Menghasilkan fungsi berguna saat Anda merancang algoritma penghitungan. Yaitu, tidak hanya ketika Anda mencari jumlah objek yang memiliki properti tertentu, tetapi juga ketika Anda sedang mencari cara untuk menyebutkan objek-objek ini (dan, mungkin, menghasilkan algoritma untuk menghitung objek). Ada presentasi yang sangat bagus di bab 7 Matematika Beton oleh Ronald Graham, Donald Knuth, dan Oren Patashnik . Contoh-contoh di bawah ini dari buku-buku ini (kesalahan dan kurangnya kejelasan adalah milik saya).
Misalkan Anda mencari cara untuk melakukan perubahan dengan set koin yang diberikan. Misalnya, dengan denominasi AS umum¹, koin yang mungkin adalah . Untuk memberi ¢ 42 dalam perubahan, satu kemungkinan adalah ; kemungkinan lain adalah . Kami akan menulis . Secara lebih umum, kita dapat menulis fungsi pembangkit untuk semua cara untuk memberikan perubahan: Dalam istilah yang lebih teknis, adalah istilah dalam ruang seri daya selama lima variabel[ 25 ] [ 10 ] [ 5 ] [ 1 ] [ 1 ] [ 10 ] [ 10 ] [ 10 ] [ 10 ] [ 10 ] [ 1 ] [ 1 ] 42 ⟨ [ 25 ] [ 10 ][1],[5],[10],[25],[100] [25][10][5][1][1] [ 10 ] [ 10 ] [ 10 ] [ 10 ] [ 1 ] [ 1 ] H = Σ h ≥ 0 Σ q ≥ 0 Σ d ≥ 0 Σ n ≥ 0 Σ p ≥ 0 [ 100 ] h [ 25 ] q [ 10 ] d [ 5 ] n [ 1 ] p42 ⟨ [ 25 ] [ 10 ] [ 5 ] [ 1 ]2⟩ = ⟨ [ 10 ]4[ 1 ]2⟩
Contoh yang lebih sulit: misalkan Anda ingin mempelajari semua cara untuk memasang persegi empat dengan 2 × 1 domino. Misalnya, ada dua cara untuk memasang persegi panjang 2 × 2, baik dengan dua domino horizontal atau dengan dua domino vertikal. Menghitung jumlah cara untuk memasang persegi panjang cukup mudah, tetapi case dengan cepat menjadi tidak terlihat. Kita dapat menghitung semua kemungkinan kemiringan pita horizontal dengan tinggi 3 dengan menempelkan domino, yang dengan cepat menghasilkan pola berulang:2 × n 3 × n
Sekali lagi, baca Matematika Beton untuk presentasi yang tidak terburu-buru³.
¹ Saya tahu daftar saya tidak lengkap; anggap AS yang disederhanakan cocok untuk contoh matematika .²
² Juga, jika muncul, anggap koin bulat.
³ Dan pengaturan huruf yang lebih baik.
sumber
Saya ingat masalah yang harus saya selesaikan selama kontes pemrograman siswa pada tahun 2001. Masalahnya adalah ini:
Saya mulai dengan loop bersarang, tetapi dengan cepat menabrak dinding. Kemudian saya menyadari bahwa saya harus mulai dengan menyebutkan apa yang dapat dilakukan dengan massa yang lebih ringan sebelum melanjutkan dengan yang lebih berat. Saya bisa memecahkan masalah dengan banyak loop yang tidak diuji.
Kalau saja saya tidak sombong dan mandiri pada masa itu (dan seandainya saya mengetahui dan mempraktikkan fungsi-fungsi pembangkit), saya mungkin telah mendefinisikan masalah dengan menghasilkan fungsi-fungsi seperti:
Tentukan sebagai OGF untuk jumlah cara yang dapat ditimbang oleh bobot berdasarkan kumpulan massa.nf( x ) n
Berapakah berat pada wajan kanan yang dapat saya timbang dengan satu massa 1?
Tiga kemungkinan:
Jadi ada satu cara untuk menimbang , satu cara untuk menimbang , dan satu cara untuk menimbang . Fungsi pembangkit untuk massa ini adalah sesuatu seperti , yang sesuai dengan:0 1 x - 1 + 1 + x- 1 0 1 x- 1+ 1+ x
Fungsi pembangkit untuk satu massa adalah , yaitu:x - m + 1 + x mm x- m+ 1 + xm
Diberi multiset massa, dinyatakan sebagai produk dari fungsi pembangkit massa tunggal:fM. f
Sekarang, mengingat paket yang dapat melakukan operasi pada polinomial, Anda hanya perlu:
Dan kamu sudah selesai. Sekarang polinomial Anda memiliki sejumlah cara untuk menimbang pada indeks . Satu-satunya masukan adalah multiset massa .w ≥ 0 w M.
Saya merancang algoritma menggunakan komponen suara secara matematis. Bagian utama dari algoritma, yang merupakan divisi polinomial dengan derajat terendah pertama, adalah linier dan dapat diimplementasikan oleh paket off-the-shelf. Ini mungkin tidak optimal, tetapi tentu saja berkinerja lebih baik daripada yang saya lakukan di kontes, dan dengan cara yang tidak terlalu banyak kesalahan.
Jika Anda mengamati proses pembagian dengan cermat, Anda dengan cepat melihat bahwa sisanya dapat dilihat sebagai "keadaan tersembunyi saat ini" di setiap keadaan proses, dan hasil bagi sebagai hasilnya. Proses berakhir ketika "keadaan tersembunyi saat ini" mencapai nol di mana-mana.
Anda dapat mengimplementasikan polinomial sebagai array atau, jika benar-benar jarang, sebagai daftar indeks-koefisien yang diurutkan, dan ini tidak akan mengubah algoritma.
sumber
Saat mengembangkan algoritma untuk maksimisasi submodular monoton di atas matroid, kami harus menyelesaikan perulangan Setelah memperhatikan bahwa , kami mengurangi masalah untuk menghitung beberapa urutan universal . Yang terakhir dicapai menggunakan fungsi menghasilkan, dan dari sana kami mendapat rumus eksplisit untuk , lagi menggunakan fungsi menghasilkan. Anda dapat menemukan solusinya di koran jika Anda penasaran, meskipun kami tidak pernah repot untuk memasukkan derivasi ini.γ ( m ) ℓ = m ( γ ( m - 1 ) ℓ - γ ( m - 1 ) ℓ - 1 ) γ ( 0 ) γ ( m )
sumber
Mungkin studi ekstensif Quicksort, dan banyak variannya, adalah contoh paling jelas. Ada pertimbangan kombinatorik mengatur pertimbangan alternatif, dan menganalisis solusi untuk persamaan yang cukup kompleks menunjukkan keunggulan kinerja (atau tidak) dari mereka.
sumber