Apa kompleksitas waktu dari algoritma ini? Dan mengapa?

8

Saya terjebak dengan menganalisis kompleksitas waktu dari algoritma berikut:

def fun (r, k, d, p):
    if d > p:
        return r
    if d = 0 and p = 0:
        r <- r + k
        return r
    if d > 0:
        fun (r, k + 1, d - 1, p)
    if p > 0:
        fun (r, k - 1, d, p - 1)

Panggilan root akan menjadi fun (0, 0, n, n), dan nmerupakan ukuran masalah.

Saya kira itu: Relasi perulangan adalah T(n,n)=T(n-1,n)+T(n,n-1), yang setara dengan , dan .T(2n)=2T(2n-1)T(m)=2T(m-1)HAI(2m)HAI(4n)

Apakah analisis saya benar (saya tahu itu tidak terlalu lengkap dan tepat)? Jika memang ada cacat serius, tunjukkan atau tunjukkan saya bukti yang benar dan lengkap tentang kompleksitas waktu dari algoritma ini.

象 嘉 道
sumber
1
xando, saya mendorong Anda untuk mengedit pertanyaan untuk menjelaskan mengapa teknik standar tidak berfungsi: jelaskan mengapa mereka gagal. (Cc: @YuvalFilmus) Misalnya, apakah Anda mendapatkan relasi perulangan yang sulit diselesaikan, dan jika demikian, perulangan apa yang Anda dapatkan?
DW
1
Dalam komentar dengan Polyergic, saya telah menyadari bahwa kodesemu tidak jelas: tidak jelas apa yang Anda maksud untuk algoritma lakukan, kapan keduanya d>0dan p>0. Anda tidak menunjukkan apa fungsi kembali jika kita mencapai pernyataan if ke-3 dan ke-4. Apakah Anda bermaksud memiliki returnpernyataan setelah setiap doa rekursif fun? (Apakah Anda bermaksud fun (r, k + 1, d - 1, p)menjadi return fun (r, k + 1, d - 1, p)?) Atau apakah Anda bermaksud memiliki returnpernyataan di akhir fungsi tubuh? Harap edit kodesemu Anda untuk memperjelas dan memastikan Anda menunjukkan apa yang dikembalikan dalam semua kasus yang mungkin.
DW
Untuk mengatakannya dengan cara lain: anggap d<=pdan d>0dan p>0semua pegang. Apa yang seharusnya terjadi? Apakah algoritma membuat 2 doa rekursif ke fungsi? Atau apakah itu secara rekursif memohon fun(r, k + 1, d - 1, p)dan kemudian segera kembali, tanpa memohon secara rekursif fun(r, k - 1, d, p - 1)? Jika saya mengambil pseudocode Anda secara harfiah, tampaknya itu membuat 2 doa rekursif dan kemudian kembali dengan nilai pengembalian yang tidak ditentukan - tapi itu aneh dan membuat saya bertanya-tanya apakah ada kesalahan ketik / bug dalam pseudocode.
DW

Jawaban:

10

Dua argumen yang relevan dengan analisis asimptotik adalah d dan hal. Argumen-argumen ini (secara virtual) memuaskand,hal0 dan dhal(kita perlu mengocok logika dalam fungsi sedikit untuk mendapatkan ini). Di setiap titik dalam eksekusi, Anda mengambil pasangan saat ini(d,hal) dan kemudian secara rekursif memanggil fungsi dengan pasangan (d-1,hal),(d,hal-1), menghindari pasangan yang membatalkan batasan yang disebutkan di atas.

Kita bisa menggambarkan pohon panggilan yang dihasilkan sebagai jalan mulai dari (0,0). Setiap kali Anda mengurangihal, tambahkan / langkah. Setiap kali Anda mengurangid, tambahkan \ langkah. Kondisidhalmenjamin bahwa Anda tidak pernah pergi di bawah sumbu X. Selain itu, Anda memiliki "anggaran" sebesarndari setiap langkah. Jumlah total daun di pohon panggilan ini persis nomor Catalan(2nn)/(n+1)=Θ(4n/n3/2), dan ini memberi kita batas bawah pada waktu menjalankan fungsi.

Untuk mendapatkan batas atas, perhatikan bahwa dalam perjalanan ke setiap daun yang kita lewati 2n node, dan ini memberi batas atas 2n lebih besar dari batas bawah, yaitu, Θ(4n/n).

Kami memiliki batas bawah Ω(4n/n3/2) dan batas atas HAI(4n/n). Apa asimptotik yang tepat? Mereka tumbuh seperti jumlah total jalur yang tidak melewati sumbu X yang paling banyaknlangkah di setiap arah. Dengan menggunakan teorema surat suara Bertrand kita bisa mendapatkan ungkapan yang tepat untuk ini:

0dhalnhal-d+1hal+1(hal+dhal).
Dengan demikian tetap untuk memperkirakan jumlah ini secara asimptotik:
0dhaln(hal+dhal)-0dhalndhal+1(hal+dd)=0dhaln(hal+dhal)-0dhaln(hal+dhal+1)=hal=0n(2hal+1hal+1)-hal=0n(2hal+1hal+2)=hal=0n1hal+1(2hal+2hal)=Θ(hal=0n4halhal3/2)=Θ(4nn3/2).
Yuval Filmus
sumber
1
Saya sangat suka pendekatan geometris Anda menggunakan "langkah" ini. Apakah itu teknik yang umum? Saya belum pernah melihatnya sebelumnya.
Andreas T
@ AndrewT Saya tidak akan menyebutnya teknik umum, memang biasanya itu tidak berlaku. Di sini interpretasi kombinatorial cukup jelas, dan itu mengarah pada solusi semacam ini.
Yuval Filmus
0

Kasus per kasus:

  1. d> p : Waktu konstan
  2. d = 0 ∧ p = 0 : Waktu konstan
  3. d> 0 : Perhatikan bahwa d ≯ p, jadi kita memiliki 0 <d ≤ p, dan funberulang pada d-1 hingga d ≯ 0; sejak p> 0, ini adalah Linear dalam d + (kasus 4) .
  4. p> 0 : Perhatikan bahwa d ≯ 0, jadi kita memiliki d ≤ 0 ≤ p (dengan d <p), dan funberulang pada p-1 hingga p ≯ 0; ini Linear dalam p + (salah satu dari kasus 1, 2, atau 5)
  5. d ≤ p <0 : Tidak terdefinisi; Saya berasumsi ini adalah waktu yang Konstan

Dimulai dengan d = p = n> 0 hits case 3, yang diikuti oleh case 4. Jika n adalah bilangan bulat, case terakhir adalah 2, jika case terakhir adalah 5. Total waktu untuk kasus tersebut adalah d + p +1, atau 2n +1.

ShadSterling
sumber
2n. Saya kira Anda kalah karena saya fokus pada alasan?
ShadSterling
1
Terima kasih telah mengedit jawabannya! Teka-teki sekarang adalah Anda menyimpulkan bahwa waktu berjalan adalahHAI(n), tetapi Yuval menyimpulkan bahwa waktu berjalan adalah eksponensial di n. Itu perbedaan yang cukup besar.
DW
1
Hmm, saya pikir saya mengambil kodesemu if s untuk menjadi "melakukan salah satu dari ini" sementara @Yuval menganggap mereka "mempertimbangkan masing-masing dalam urutan". Yang terakhir, tentu saja, apa artinya if(tanpa else) dalam kode aktual; Saya terbiasa dengan yang pertama dalam hampir semua konteks selain kode aktual (termasuk dalam pseudocode, meskipun penggunaan dalam pseudocode tidak konsisten).
ShadSterling
Saya mengerti apa yang kamu maksud. Kurangnya returnpernyataan di bagian akhir kode membuat ini sangat membingungkan.
DW