Dengan bilangan bulat 2n, temukan jumlah cara yang memungkinkan dimana 2n ^ 2 pion hitam dan 2n ^ 2 pion putih dapat diatur pada papan catur 2n oleh 2n sehingga tidak ada pion yang menyerang pion lain.
- Gadai hitam hanya bisa menyerang gadai putih, dan sebaliknya.
- Aturan serangan catur yang biasa diikuti, yaitu, kotak serangan pion putih langsung diagonal di depan, dan kotak serangan pion hitam segera mundur secara diagonal (seperti yang terlihat oleh pengamat kulit putih).
- Semua rotasi, jumlah pantulan berbeda.
Program yang dapat menampilkan semua konfigurasi yang memungkinkan untuk nilai tertinggi 2n dalam 120 detik akan menang. (Namun, semua program dipersilahkan)
Misalnya, program Alice dapat menangani hingga n = 16 dalam 120 detik sementara Bob dapat menangani hingga n = 20 dalam waktu yang sama. Bob menang.
Platform: Linux 2.7GHz @ 4 CPU
fastest-code
combinatorics
chess
Agnishom Chattopadhyay
sumber
sumber
2n^2
pion, apakah itu(2n)^2
atau2(n^2)
?Jawaban:
Java, n = 87 di mesin saya
Hasil untuk n = 87 adalah
Ini saat ini menggunakan skema pemrograman dinamis yang mengambil operasi O (n ^ 4) untuk menghitung cara menempatkan
p
pion pada kotak dengan satu warna0 <= p <= n^2
. Saya pikir ini harus dilakukan dengan lebih efisien.Lihat hasilnya di sini.
Penjelasan
Dalam solusi yang valid, pion putih paling bawah di setiap kolom harus membentuk garis zig-zag seperti ini:
Yaitu, ketinggian garis dalam kolom c harus +/- 1 dari posisinya di kolom c - 1 . Garis juga dapat menuju ke dua baris imajiner di atas bagian atas papan.
Kita dapat menggunakan pemrograman dinamis untuk menemukan sejumlah cara untuk menarik garis pada pertama c kolom yang mencakup p bidak pada kolom tersebut, berada pada ketinggian h di c th kolom, menggunakan hasil untuk kolom c - 1 , ketinggian h + / - 1 , dan jumlah pion p - h .
sumber
Jawa
Saat ini, kode saya sangat panjang dan membosankan, saya sedang berusaha membuatnya lebih cepat. Saya menggunakan metode rekursif untuk menemukan nilai-nilai. Ini menghitung 5 pertama dalam 2 atau 3 detik, tetapi kemudian menjadi lebih lambat. Juga, saya belum yakin apakah angkanya tepat, tetapi beberapa yang pertama tampaknya sejalan dengan komentar. Setiap saran dipersilahkan.
Keluaran
Penjelasan
Ide dasarnya adalah rekursi. Pada dasarnya Anda mulai dengan papan kosong, papan dengan semua nol. Metode rekursif hanya memeriksa untuk melihat apakah itu dapat menempatkan pion hitam atau putih di posisi berikutnya, jika hanya dapat menempatkan satu warna, ia meletakkannya di sana dan memanggil dirinya sendiri. Jika itu dapat menempatkan kedua warna itu menyebut dirinya dua kali, satu dengan masing-masing warna. Setiap kali itu menyebut dirinya mengurangi kuadrat kiri dan warna yang sesuai tersisa. Ketika telah mengisi seluruh papan, ia mengembalikan hitungan saat ini + 1. Jika ternyata tidak ada cara untuk meletakkan pion hitam atau putih di posisi berikutnya, ia mengembalikan 0, yang berarti itu adalah jalan mati.
Kode
Cobalah di sini (Tidak berjalan cukup cepat untuk Ideone sehingga nilai terakhir tidak dicetak, sepertinya solusi saya tidak terlalu bagus!)
sumber
C ++ dengan pthreads, n =
147156Hasil terbaru adalah dari menjalankan kode yang sama seperti sebelumnya pada mesin yang lebih gemuk. Ini sekarang dijalankan pada desktop dengan quad-core i7 (Core i7-4770), yang mencapai n = 156 dalam 120 detik. Hasilnya adalah:
Ini menggunakan algoritma pemrograman dinamis. Saya awalnya merenungkan pendekatan di mana hasilnya akan dibangun baris demi baris, tetapi saya tidak pernah bisa menemukan cara untuk memperluas solusi tanpa melacak satu ton negara.
Wawasan utama yang memungkinkan solusi yang cukup efisien adalah:
Jika Anda melihat satu diagonal dari konfigurasi yang valid, itu selalu terdiri dari urutan pion hitam diikuti oleh urutan pion putih (di mana salah satu urutan juga bisa kosong). Dengan kata lain, masing-masing diagonal dapat sepenuhnya ditandai oleh jumlah pion hitamnya.
Oleh karena itu, status yang dilacak untuk setiap diagonal adalah jumlah konfigurasi gadai yang valid untuk setiap kombinasi:
Ketika melangkah dari satu diagonal ke yang berikutnya, ada kendala lain untuk membangun solusi yang valid: Posisi yang memisahkan pion hitam dari pion putih tidak dapat meningkat. Jadi jumlah konfigurasi yang valid dihitung sebagai jumlah dari konfigurasi yang valid dari diagonal sebelumnya untuk posisi yang sama atau lebih besar.
Langkah dasar DP kemudian sangat sederhana. Setiap nilai dalam diagonal hanyalah jumlah nilai dari diagonal sebelumnya. Satu-satunya bagian yang agak menyakitkan adalah menghitung indeks dan rentang loop dengan benar. Karena kita sedang mengerjakan diagonal, panjangnya bertambah selama paruh pertama perhitungan, dan berkurang untuk paruh kedua, yang membuat perhitungan rentang loop lebih rumit. Ada juga beberapa pertimbangan untuk nilai-nilai di batas papan, karena mereka hanya memiliki tetangga diagonal di satu sisi ketika melangkah dari diagonal ke diagonal.
Jumlah memori yang digunakan adalah O (n ^ 3). Saya menyimpan dua salinan data negara, dan ping pong di antara mereka. Saya percaya itu akan mungkin untuk beroperasi dengan satu contoh data negara. Tetapi Anda harus sangat berhati-hati agar tidak ada nilai yang diperbarui sebelum nilai lama dikonsumsi sepenuhnya. Juga, itu tidak akan bekerja dengan baik untuk pemrosesan paralel yang saya perkenalkan.
Kompleksitas runtime adalah ... jumlahnya banyak. Ada 4 loop bersarang dalam algoritma, jadi pada pandangan pertama akan terlihat seperti O (n ^ 4). Tetapi Anda jelas membutuhkan bigints pada ukuran ini, dan angkanya sendiri juga lebih panjang pada ukuran yang lebih besar. Jumlah digit dalam hasil tampaknya meningkat secara proporsional ke n, yang akan membuat semuanya O (n ^ 5). Di sisi lain, saya menemukan beberapa peningkatan kinerja, yang menghindari melalui semua loop penuh.
Jadi sementara ini masih merupakan algoritma yang cukup mahal, ia menjadi lebih jauh dari algoritma yang menyebutkan solusi, yang semuanya eksponensial.
Beberapa catatan implementasi:
Kode algoritma utama.
THREADS
mengontrol jumlah utas yang digunakan, di mana jumlah inti CPU harus menjadi titik awal yang masuk akal:Ini juga membutuhkan kelas bigint yang saya tulis untuk tujuan ini. Perhatikan bahwa ini bukan tujuan umum kelas bigint. Itu hanya cukup untuk mendukung operasi yang digunakan oleh algoritma spesifik ini:
sumber
Fantom
Berikut ini adalah pos awal yang mengatur kerangka kerja. Saya pikir prosedurnya relatif bagus, tetapi implementasinya saat ini agak menyebalkan. Saya mungkin perlu mencoba untuk meminimalkan jumlah perhitungan yang saya lakukan, dan alih-alih hanya memberikan lebih banyak konstanta.
Strategi
Pada dasarnya, setiap pion putih harus menyerang pion putih lainnya. Jadi saya mulai dengan menempatkan pion putih, menempatkan pion di setiap tempat yang diserang, dan pada dasarnya mengisi papan dengan semua tempat yang harus dituju oleh pion putih. Saya berhenti jika saya sudah menambahkan terlalu banyak pion putih. Jika, pada akhir ini, saya memiliki persis 2n ^ 2 pion, itu solusi. Jika kurang dari itu, tambahkan pion putih lain di suatu tempat, isi semua tempat yang diperlukan, dan hitung lagi. Saya membagi secara rekursif setiap kali isi dengan kurang dari 2n ^ 2 ditemukan, dan menghitung jumlah solusi dengan dan tanpa pion terakhir yang saya tambahkan.
Kode
Keluaran
Hanya membuatnya menjadi 5 sekarang, tapi saya pikir sebagian besar masalah dalam implementasi.
Uji
sumber