Saya sedang mengerjakan perangkat lunak untuk mesin yang secara otomatis akan memotong kuku kaki, sehingga pengguna dapat dengan mudah meletakkan kaki mereka di dalamnya dan menjalankannya daripada harus melakukannya secara manual dengan menggigitnya atau menggunakan gunting kuku.
Persentase yang cukup besar dari basis pengguna potensial kami kemungkinan besar adalah orang Yahudi, dan, jelas, ada tradisi untuk tidak memotong kuku kaki ( atau kuku ) secara berurutan
Tampaknya ada perbedaan pendapat tentang penerapan yang tepat dari tradisi ini, tetapi menurut kami aturan berikut cukup untuk mengakomodasi orang-orang yang praktik keagamaannya melarang pemotongan kuku secara berurutan:
- Tidak ada dua kuku kaki yang berdekatan harus dipotong secara berurutan
- Urutan pemotongan di kaki kiri harus tidak sesuai dengan urutan di kaki kanan
- Urutan pemotongan pada dua proses berturut-turut tidak boleh sama. Urutan seharusnya tidak mudah diprediksi, jadi pengkodean keras urutan alternatif tidak berfungsi.
Beginilah cara kami memutuskan untuk memberi nomor pada jari kaki:
5 4 3 2 1 1 2 3 4 5
Left foot Right foot
Saya telah menulis kode untuk menyelesaikan masalah, tetapi algoritma yang digunakan kurang optimal: pada kenyataannya, kinerja kasus terburuk adalah O (∞) . Cara kerjanya sebanding dengan bogosort . Berikut ini adalah penyederhanaan pseudocode dari kode sebenarnya yang digunakan:
function GenerateRandomSequence
sequence = Array[5]
foreach (item in sequence)
item = RandomNumberBetween(1,5)
return sequence
function GetToenailCuttingOrder
while (true)
sequence = GenerateRandomSequence()
if (!AllItemsAreUnique(sequence))
continue
if (NoTwoAdjacentItemsHaveConsecutiveNumbers(sequence))
return sequence
do
leftFootSequence = GetToenailCuttingOrder()
rightFootSequence = GetToenailCuttingOrder()
until (leftFootSequence != rightFootSequence &&
leftFootSequence != leftFootSequenceFromLastRun &&
rightFootSequence != rightFootSequenceFromLastRun)
Pada dasarnya, ini menghasilkan urutan acak dan memeriksa apakah memenuhi kriteria. Jika tidak memenuhi kriteria, itu akan dimulai kembali. Ini tidak membutuhkan waktu yang sangat lama, tetapi sangat tidak terduga.
Saya menyadari bahwa cara yang saya lakukan saat ini sangat buruk, tetapi saya kesulitan menemukan cara yang lebih baik. Adakah di antara Anda yang dapat menyarankan algoritme yang lebih elegan dan berperforma baik?
sumber
Jawaban:
Anda dapat membuat semua urutan pemotongan kuku yang mungkin tanpa batasan, dan kemudian memfilter semua urutan yang melanggar aturan Yahudi. Untungnya, manusia hanya memiliki lima jari per kaki *, jadi hanya ada 5! = 120 urutan tidak terbatas.
Contoh Python:
Untuk menegakkan aturan "jangan berulang dalam urutan yang sama", Anda cukup memilih empat dari urutan di atas, dan menggunakannya secara bergantian. Satu-satunya batasan di sini adalah jika Anda menghitung dua jari kaki besar sebagai "berurutan", maka Anda tidak dapat memilih dua urutan yang berakhir dan dimulai dengan 1, masing-masing.
* Anda mungkin ingin membuat variabel numberOfToesPerFoot, sehingga Anda dapat dengan mudah mengubahnya nanti jika salah satu klien Anda ternyata memiliki jari kaki lebih sedikit dari yang Anda harapkan, atau lebih.
sumber
Ada sejumlah urutan terbatas yang memenuhi kebutuhan Anda.
EDIT: Jika ini bukan tentang jari-jari kaki, tetapi tentang beberapa masalah acak di mana himpunan bisa jauh lebih besar dari 5, ruang urutan menjadi sangat besar dan peluang untuk mengulangi urutan yang sama pada kaki kedua menjadi sangat kecil. Jadi membuat urutan secara acak dan menolaknya jika cocok adalah ide yang bagus. Menghasilkan urutan acak menurut beberapa aturan seperti "lompat dengan dua atau tiga, lalu isi yang kosong" mungkin akan lebih cepat daripada menghasilkan permutasi dan pengujian acak, dan kemungkinan tumpang tindih akan tetap kecil jika jumlah "jari kaki" besar .
sumber
Sebenarnya, saya paling menyukai algoritme asli Anda.
Karena 14 dari 120 permutasi berfungsi, 106 dari 120 tidak. Jadi, setiap cek memiliki peluang 106/120 untuk gagal.
Itu berarti jumlah kegagalan yang diharapkan adalah:
Tidak terlalu sulit untuk menjumlahkan seri infinite ini:
Kalikan dengan x:
Mengurangi:
Kalikan dengan x lagi dan kurangi lagi:
Karena x = 106/120, S = 64,9.
Jadi, rata-rata loop Anda hanya membutuhkan 65 iterasi untuk menemukan solusi.
Berapa probabilitas yang dibutuhkan, katakanlah, seribu iterasi?
Nah, kemungkinan gagal satu iterasi tunggal adalah 104/120, jadi kemungkinan gagal 1000 iterasi adalah (104/120) ^ 1000, yang kira-kira 10 ^ (- 63). Artinya, Anda tidak akan pernah melihatnya terjadi dalam hidup Anda, dan mungkin tidak dalam seumur hidup alam semesta.
Tidak ada tabel yang telah dihitung sebelumnya, mudah beradaptasi dengan jumlah jari / jari kaki / tangan / kaki yang berbeda, mudah beradaptasi dengan aturan yang berbeda ... Apa yang tidak disukai? Peluruhan eksponensial adalah hal yang luar biasa.
[memperbarui]
Ups, saya salah mendapatkan rumus aslinya ... Karena probabilitas saya tidak berjumlah 1. :-)
Ekspresi yang benar untuk jumlah kegagalan yang diharapkan adalah:
(Misalnya, untuk mendapatkan tepat dua kegagalan, Anda memerlukan dua kegagalan diikuti dengan kesuksesan . Dua kegagalan memiliki probabilitas (106/120) ^ 2; satu kesuksesan memiliki probabilitas (14/120); kalikan keduanya untuk mendapatkan bobot untuk Istilah "2".)
Jadi S saya mati dengan faktor (1-x) (yaitu, 14/120). Jumlah kegagalan yang diharapkan sebenarnya hanya x / (1-x) = 106/14 = 7,57. Jadi rata-rata hanya butuh 8-9 iterasi untuk menemukan solusi (7,5 kegagalan plus satu sukses).
Matematika saya untuk kasus "1000 kegagalan" masih benar, saya kira.
sumber
Yang jelas: Temukan satu pesanan yang berhasil, dan buat kode keras. Tapi saya rasa Anda tidak ingin melakukan itu.
Anda dapat menghasilkan permutasi jauh lebih baik daripada cara Anda melakukannya. Anda tidak perlu melakukan pengambilan sampel penolakan. Gunakan pengacakan Fisher Yates pada permutasi yang diurutkan awal (1, 2, .. 5), dan Anda akan memiliki permutasi acak. http://en.wikipedia.org/wiki/Fisher%E2%80%93Yates_shuffle
Tetapi secara umum, metode hasilkan dan uji tampaknya baik-baik saja bagi saya, selama kemungkinan menghasilkan entri yang berhasil cukup tinggi. Saya yakin ada banyak urutan yang valid sesuai dengan kriteria Anda, begitu Anda beralih ke permutasi acak, saya ragu Anda harus melakukan banyak iterasi penolakan.
sumber
Tidak ada yang benar-benar baru di sini, solusi yang sama @Kevin sudah diposting, tapi saya pikir menarik untuk melihat bagaimana diterjemahkan ke bahasa fungsional. Dalam hal ini, Mathematica :
Beberapa penjelasannya:
Hasil akhirnya adalah:
Sunting
Atau, lebih sulit untuk dijelaskan, tetapi lebih singkat:
sumber
Sebenarnya tidak ada alasan untuk memasukkan keacakan ke dalam masalah ini. Hanya ada 14 urutan yang memenuhi masalah ini, dan tentunya beberapa urutan urutan tersebut akan paling memuaskan rasa estetika yang Anda coba tampung. Jadi, Anda sebaiknya mengurangi masalah ini menjadi algoritme untuk memilih urutan dari 14 itu, mungkin dalam urutan yang telah ditentukan sebelumnya.
Implementasi Javascript dari algoritma untuk menemukan 14:
EDIT: Persyaratan baru bahwa urutan harus dibuat secara acak tidak dapat dengan mudah dipenuhi. Hal terbaik yang mungkin dapat Anda lakukan adalah membuatnya menjadi pseudorandom, yang sama deterministiknya dengan hard-coding sebelumnya, dan karenanya tidak memuaskan takhayul siapa pun.
sumber