Ringkasan bisnis plan
Input yang diberikan k
, cari partisi bilangan bulat 1
ke n
dalam k
subset bebas jumlah untuk yang terbesar n
yang dapat Anda lakukan dalam 10 menit.
Latar belakang: Nomor Schur
Himpunan A
adalah jumlah bebas jika jumlah sendiri A + A = { x + y | x, y in A}
tidak memiliki elemen yang sama dengannya.
Untuk setiap bilangan bulat positif k
ada bilangan bulat terbesar S(k)
sehingga himpunan {1, 2, ..., S(k)}
dapat dipartisi menjadi k
himpunan bagian bebas jumlah. Jumlah ini disebut k th jumlah Schur (Oei A045652 ).
Misalnya S(2) = 4
,. Kita dapat mempartisi {1, 2, 3, 4}
sebagai {1, 4}, {2, 3}
, dan itu adalah partisi unik menjadi dua himpunan bagian jumlah bebas, tetapi sekarang kita tidak dapat menambahkan 5
ke bagian mana pun.
Tantangan
Tulis program deterministik yang melakukan hal berikut:
- Ambil bilangan bulat positif
k
sebagai input - Tulis stempel waktu Unix saat ini ke stdout
- Keluarkan urutan partisi
1
menjadin
kek
subset bebas jumlah untuk bertambahn
, mengikuti setiap urutan dengan cap waktu Unix saat ini.
Pemenangnya adalah program yang mencetak partisi terbesar n
dalam waktu 10 menit di komputer saya ketika diberi input 5
. Ikatan akan terputus dengan waktu tercepat untuk menemukan partisi untuk yang terbesar n
, rata-rata lebih dari tiga kali: itu sebabnya output harus menyertakan cap waktu.
Detail penting:
- Saya memiliki Ubuntu Precise, jadi jika bahasa Anda tidak didukung, saya tidak akan bisa menilai itu.
- Saya memiliki Intel Core2 Quad CPU, jadi jika Anda ingin menggunakan multithreading tidak ada gunanya menggunakan lebih dari 4 utas.
- Jika Anda ingin saya menggunakan flag compiler atau implementasi tertentu, dokumentasikan dengan jelas dalam jawaban Anda.
- Anda tidak akan membuat kasus khusus kode Anda untuk menangani input
5
. - Anda tidak perlu menampilkan setiap peningkatan yang Anda temukan. Misalnya untuk input,
2
Anda hanya bisa menampilkan partisi untukn = 4
. Namun, jika Anda tidak menghasilkan apa pun dalam 10 menit pertama maka saya akan menilai itu sebagain = 0
.
sumber
n=59
, dan penyortiran oleh jumlah terbesar nomor diperbolehkan kurang darinextN
memberin=64
. Mengurutkan berdasarkan panjang daftar angka yang tidak diizinkan (yang mungkin memiliki pengulangan) mengarah sangat cepat ken=30
pola yang elegan .Tue Nov 10 00:44:25 2015
), tapi saya melihatn=92
dalam waktu kurang dari 2 detik.ctime
lebihtime
karena output lebih cantik ketikatime
itu persis apa yang saya harus sudah memilih.n=121
. oOPython 3, 121, <0,001s
Peningkatan heuristik berkat Martin Buttner berarti kita bahkan tidak perlu keacakan.
Keluaran:
Kode:
Python 3, 112
Urutkan berdasarkan jumlah dari 2 elemen pertama + condong
Saya menyalin struktur data El'endia Starman, yang terdiri dari daftar pasangan, di mana elemen pertama dari pasangan adalah elemen dalam ember itu, dan yang kedua adalah jumlah dari ember itu.
Saya mulai dengan pendekatan "lacak jumlah yang tersedia" yang sama. Heuristik sorting saya hanyalah jumlah dari dua elemen terkecil dalam daftar yang diberikan. Saya juga menambahkan condong acak kecil untuk mencoba berbagai kemungkinan.
Setiap iterasi hanya menempatkan setiap nomor baru di nampan pertama yang tersedia, mirip dengan serakah acak. Setelah ini gagal, itu hanya restart.
sumber
Java 8, n =
142144Output terakhir:
Melakukan pencarian acak unggulan yang didistribusikan di lebih dari 4 utas. Ketika tidak dapat menemukan partisi yang cocok,
n
ia mencoba untuk membebaskan ruangn
dalam satu partisi pada satu waktu dengan membuang sebanyak mungkin dari itu ke partisi lain.sunting: tweak algoritma untuk membebaskan ruang untuk
n
, juga menambahkan kemampuan untuk kembali ke pilihan sebelumnya dan memilih lagi.catatan: output tidak sepenuhnya deterministik karena ada beberapa utas yang terlibat dan mereka akhirnya memperbarui yang terbaik yang
n
ditemukan sejauh ini dalam urutan yang campur aduk; skor akhirnya 144 adalah deterministik dan dicapai dengan cukup cepat: 30 detik di komputer saya.Kode adalah:
sumber
C, serakah acak, n = 91
Hanya untuk memberikan solusi dasar, ini berulang
n
, melacak sampah dan jumlah mereka dan menambahkann
ke bin acak di mana ia belum muncul sebagai jumlah. Ini berakhir sekalin
muncul dalam semuak
jumlah, dan jika hasilnyan
lebih baik daripada upaya sebelumnya, mencetaknya ke STDOUT.Input
k
diberikan melalui argumen baris perintah. Maksimum yang mungkink
saat ini hardcoded ke 10 karena saya terlalu malas menambahkan alokasi memori dinamis, tetapi itu bisa diperbaiki dengan mudah.Saya kira saya bisa pergi berburu benih yang lebih baik sekarang, tapi jawaban ini mungkin tidak terlalu kompetitif, jadi meh.
Ini adalah partisi untuk
n = 91
:Dan akhirnya, inilah kodenya:
sumber
n=91
, ditemukan dalam 138 detik. Jika perlu untuk tie-breaking saya akan retime untuk menghindari kesalahan besar karena beban CPU yang berbeda.C ++, 135
Tambahkan n berikutnya ke subset yang dipilih secara acak. Jika itu tidak memungkinkan, ia menghapus angka acak dari himpunan bagian dan menambahkannya ke orang lain dengan harapan hal itu memungkinkan penambahan di suatu tempat.
Saya membuat prototipe dalam awk, dan karena terlihat menjanjikan, saya menerjemahkannya ke dalam C ++ untuk mempercepatnya. Menggunakan
std::set
bahkan harus mempercepat lebih.Output untuk n = 135 (setelah sekitar 230 detik pada mesin [lama] saya)
Saya tidak memeriksa ulang validitasnya, tetapi seharusnya tidak apa-apa.
sumber
Python 3, serakah acak, n = 61
Output terakhir:
Ini menggunakan secara efektif algoritma yang sama dengan algoritma Martin Büttner , tetapi saya mengembangkannya secara independen.
Ada
k
tempat sampah yang memiliki nomor di dalamnya sejauh ini dan nomor yang tidak bisa masuk lagi. Pada setiap kedalaman dalam iterasi (pada dasarnya ini adalah pencarian mendalam-pertama), pemesanan bin dikocok dan nomor berikutnyanextN
() dimasukkan (secara berurutan) ke dalam tempat sampah yang dapat mengambilnya dan kemudian melangkah lebih dalam satu langkah. Jika tidak ada, itu kembali, mendukung satu langkah.sumber
Python, n = 31
Ok, jadi itu obvisouly bukan pemenang, tetapi saya merasa itu milik di sini pula. Saya telah mengambil kebebasan untuk tidak memasukkan stempel waktu, karena itu berakhir secara instan, dan karena itu bukan pesaing nyata.
Pertama, perhatikan bahwa jumlah dua angka ganjil mana pun adalah genap, sehingga kami dapat membuang semua angka ganjil di blok pertama. Kemudian, karena semua angka yang tersisa adalah genap, kita dapat membaginya dengan 2. Sekali lagi, kita dapat membuang semua angka ganjil yang dihasilkan di blok kedua (setelah mengalikannya dengan 2), membagi angka yang tersisa dengan 2 (yaitu , dengan 4 keseluruhan), melempar yang aneh di blok ketiga (setelah mengalikannya dengan 4), dan seterusnya ... Atau, dengan kata-kata yang kalian mengerti, kami menempatkan semua angka yang set paling tidak signifikan bit adalah bit pertama di blok pertama, semua angka yang bit set paling tidak signifikan adalah bit kedua di blok kedua, dan seterusnya ...
Untuk blok k , kita mengalami masalah setelah mencapai n = 2 k , karena bit set paling tidak signifikan dari n adalah bit
( k + 1) -th, yang tidak sesuai dengan blok mana pun. Dengan kata lain, skema ini bekerja sampai
ke n = 2 k - 1. Jadi, sedangkan untuk k = 5 kita hanya mendapatkan sedikit n = 31 , jumlah ini tumbuh secara eksponensial dengan k . Ini juga menetapkan bahwa S ( k ) ≥ 2 k - 1 (tetapi kita sebenarnya dapat menemukan batas bawah yang lebih baik daripada itu dengan mudah.)
Untuk referensi, inilah hasil untuk k = 5:
sumber
[1], [2,3], [4,5,6,7], ...
, yang mungkin lebih sederhana, hanya dengan bit terbalik dan ketertiban blok. Sangat mudah untuk melihat bagaimana ini dapat diperpanjang.