"Peretas" atas nama pengujian menyarankan agar kami mencoba menemukan solusi berorientasi komputasi.
Karena itu, mari kita mulai dengan program untuk penghitungan kasar (a) kasus "menguntungkan" di mana satu bilangan bulat dua kali lainnya dan (b) semua kasus yang mungkin. Jawabannya kemudian akan menjadi rasio mereka. Saya telah mengkodekan solusi umum. Inputnya adalah bilangan bulat positif n
dan hasilnya adalah probabilitas.
n=100
all=favorable=0
for i=1 to n
for j=1 to n
if (i != j) all=all+1 {1}
if (j == 2*i) favorable = favorable+1 {2}
if (i == 2*j) favorable = favorable+1 {3}
return(favorable / all)
(Bukti kebenaran bergantung pada fakta bahwa untuk angka positif .)i≠2ii
Program ini membutuhkan tes dan hingga peningkatan untuk setiap iterasi loop dalam. Oleh karena itu diperlukan perhitungan antara dan setiap kali loop dalam dilakukan, atau keseluruhan hingga . Itu kinerja : OK untuk kecil seperti , tapi mengerikan sekali melebihi atau lebih.333n6n3n26n2O(n2)nn=100n10000
Sebagai seorang hacker, salah satu hal pertama yang ingin Anda lakukan adalah menghilangkan kinerja kuadratik dengan menyederhanakan loop dalam (jika mungkin). Untuk tujuan ini, secara sistematis melalui garis-garis di loop dalam (seperti bernomor) dan perhatikan hal berikut:
Baris 1 dieksekusi semua kecuali satu kali untuk setiap nilai i
dan karenanya all
bertambah kali. Akibatnya, untuk perhitungan , loop over dapat diganti dengan bertambahnya oleh .n−1all
j
all
n-1
Baris 2 dieksekusi tepat sekali ketika dan sebaliknya tidak sama sekali. Oleh karena itu dapat diganti dengan incrementing oleh setiap kali .2i≤nall
12i≤n
Baris 3 dijalankan setelah disediakan i
bahkan.
Berikut adalah program yang diubah.
n=100
all=favorable=0
for i=1 to n
all = all + (n-1) {1'}
if (2*i <= n) favorable = favorable+1 {2'}
if (even(i)) favorable = favorable+1 {3'}
return(favorable / all)
Bisakah kita melangkah lebih jauh dan menghilangkan lingkarannya?
Baris 1 'dijalankan kali. Oleh karena itu ditambahkan oleh .nall
n*(n-1)
Baris 2 'dieksekusi hanya ketika . Salah satu cara untuk menghitung ini adalah (bilangan bulat terbesar kurang dari atau sama dengan ).2i≤n⌊n/2⌋n/2
Baris 3 'dijalankan hanya untuk nilai genap . Sekali lagi, itu terjadi kali.i⌊n/2⌋
Transformasi kedua dari program ini adalah:
n=100
all=favorable=0 {0}
all = all + n * (n-1) {1''}
favorable = favorable + floor(n/2) {2''}
favorable = favorable + floor(n/2) {3''}
return(favorable / all)
Ini sudah merupakan prestasi yang luar biasa: a algoritma telah direduksi menjadi algoritma (yang dapat dianggap sebagai "formula tertutup" untuk jawabannya).O(n2)O(1)
Akhirnya, ada beberapa transformasi aljabar sederhana yang dapat kita lakukan dengan menggulir inisialisasi (baris 0) menjadi penggunaan pertama dari setiap variabel dan menggabungkan garis 2 '' dan 3 '':
n=100
all = n * (n-1)
favorable = 2 * floor(n/2)
return(favorable / all)
Pada titik ini manusia dapat menjalankan program. Mari kita lakukan dengan :n=100
all = 100 * (100-1) = 100*99
favorable = 2 * floor(100/2) = 2*50 = 100
favorable/all = 100 / (100*99) = 1/99
Outputnya adalah .1/99
Untuk meringkas, algoritma brute-force dapat ditransformasikan secara sistematis menggunakan aturan penulisan ulang program sederhana menjadi program ramping, anggun .O(1)