Teka-teki sisi depan atas adalah teka-teki di mana Anda harus membuat bentuk 3-D dari blok (biasanya kubik) yang diberikan tiga tampilan ortogonal: tampilan atas, tampilan depan, dan tampilan samping.
Misalnya, diberi tampilan atas, depan, dan samping sebagai berikut:
Top: Front: Side:
. . . . . . . . . . . .
. x x . . x x . . x x .
. x x . . x x . . x x .
. . . . . . . . . . . .
In this problem, the side view is taken from the right.
Kubus 2x2x2 (dengan volume 8) akan memuaskan solusi ini, tetapi itu bisa dilakukan dalam volume 4, jika kita memiliki struktur lapisan berikut:
. . . . . . . .
. x . . . . x .
. . x . . x . .
. . . . . . . .
Ada juga beberapa pengaturan yang tidak dapat diselesaikan. Ambil, misalnya:
Top: Front: Side:
. . . . . . . . . . . .
. . . . . . x . . . . .
. x . . . . . . . x . .
. . . . . . . . . . . .
Jika tampilan atas mengatakan blok kedua dari kiri, tidak ada cara yang bisa cocok dengan tampilan depan yang mengatakan blok harus ketiga dari kiri. Jadi pengaturan ini tidak mungkin.
Tugas Anda adalah membangun sebuah program yang, mengingat teka-teki sisi-atas 4x4 sewenang-wenang, mencoba menyelesaikannya dalam jumlah paling sedikit kubus, atau menyatakannya tidak dapat dipecahkan.
Program Anda akan mengambil sebagai input serangkaian 48 bit, mewakili tampilan atas, depan, dan samping. Mereka mungkin dalam format apa pun yang Anda inginkan (string 6-byte, string 0 dan 1, angka hex 12-digit, dll.), Tetapi urutan bit harus dipetakan seperti itu:
Top: 0x00 Front: 0x10 Side: 0x20
0 1 2 3 0 1 2 3 0 1 2 3
4 5 6 7 4 5 6 7 4 5 6 7
8 9 a b 8 9 a b 8 9 a b
c d e f c d e f c d e f
Dengan kata lain, bitnya berada dalam urutan kiri-ke-kanan, atas-ke-bawah, di atas, lalu depan, lalu samping.
Program Anda kemudian akan menampilkan serangkaian 64 bit yang mengindikasikan kubus dalam kisi 4x4x4 yang diisi, atau menunjukkan bahwa kisi tersebut tidak dapat dipecahkan.
Program Anda akan dinilai dengan menjalankan baterai 1.000.000 kasus uji.
Data pengujian akan dihasilkan dengan mengambil hash MD5 dari bilangan bulat "000000" hingga "999999" sebagai string, mengekstraksi 48 bit pertama (12 heksit) dari masing-masing hash ini, dan menggunakannya sebagai input untuk front-front- teka-teki sisi. Sebagai contoh, berikut adalah beberapa input tes dan puzzle yang mereka hasilkan:
Puzzle seed: 000000 hash: 670b14728ad9
Top: Front: Side:
. x x . . . . x x . . .
x x x x . x . x x . x .
. . . . . x x x x x . x
x . x x . . x . x . . x
Puzzle seed: 000001 hash: 04fc711301f3
Top: Front: Side:
. . . . . x x x . . . .
. x . . . . . x . . . x
x x x x . . . x x x x x
x x . . . . x x . . x x
Puzzle seed: 000157 hash: fe88e8f9b499
Top: Front: Side:
x x x x x x x . x . x x
x x x . x . . . . x . .
x . . . x x x x x . . x
x . . . x . . x x . . x
Dua yang pertama tidak dapat dipecahkan, sedangkan yang terakhir memiliki solusi dengan lapisan berikut, dari depan ke belakang:
x . . . . . . . x x x . x x x .
. . . . x . . . . . . . . . . .
x . . . . . . . . . . . x x x x
x . . . . . . . . . . . x . . x
There are a total of 16 blocks here, but it can probably be done in less.
Skor program Anda akan ditentukan oleh kriteria berikut, dalam urutan prioritas menurun:
- Jumlah tertinggi kasus yang diselesaikan.
- Jumlah blok terendah yang diperlukan untuk menyelesaikan kasus-kasus tersebut.
- Kode terpendek dalam byte.
Anda harus menyerahkan dan menghitung skor sendiri, yang mengharuskan program Anda dapat menjalankan semua 1.000.000 kasus uji.
Jawaban:
Python: 5360 kasus uji dipecahkan menggunakan 69519 blok, 594 byte
Ini harus menjadi nilai optimal.
Pendekatan:
Pertama saya akan menguji apakah test case-nya benar-benar bisa dipecahkan. Saya melakukan ini dengan menginisialisasi daftar panjang 64 oleh yang dan mengatur semua posisi ke nol, jika ada pixel yang sesuai dari tiga tampilan adalah nol. Lalu saya sederhana melihat puzzle dari ketiga arah, dan melihat apakah pandangannya sama dengan pandangan input. Jika ada yang sama, puzzle dapat dipecahkan (kami sudah menemukan solusi terburuk), jika tidak maka tidak dapat dipecahkan.
Lalu saya melakukan pendekatan cabang-dan-terikat untuk menemukan solusi optimal.
Bercabang: Saya memiliki fungsi rekursif. Kedalaman rekursi memberitahu berapa banyak nilai yang sudah diperbaiki. Dalam setiap panggilan fungsi saya memanggil dirinya dua kali, jika nilai pada indeks saat ini adalah 1 (nilai ini bisa 0 atau 1 dalam solusi optimal), atau sekali, jika nilainya 0 (harus nol dalam solusi optimal).
Bounding: Saya menggunakan dua strategi berbeda di sini.
Saya menghitung tampilan dari 3 sisi dalam setiap panggilan fungsi dan mencari apakah masih cocok dengan nilai input. Jika tidak cocok, saya tidak memanggil fungsi secara rekursif.
Saya menyimpan solusi terbaik dalam memori. Itu sudah ada yang lebih tetap di cabang saat ini daripada di solusi terbaik, saya sudah bisa menutup cabang itu. Selain itu saya dapat memperkirakan batas bawah untuk jumlah blok yang diaktifkan, yang tidak diperbaiki. Dan kondisinya menjadi
#number of activated fixed blocks + #lower bound of activated blocks (under the not fixed blocks) < #number of activated blocks in the best solution.
Ini kode Python. Ini mendefinisikan fungsi
f
yang mengharapkan 3 daftar yang berisi 1s dan 0s dan mengembalikan 0 (tidak dapat dipecahkan) atau daftar 1s dan 0s yang mewakili solusi optimal.Panjang kode adalah 596 byte / karakter. Dan inilah kerangka tesnya:
Anda dapat menemukan versi program yang tidak diklik di sini . Ini juga sedikit lebih cepat.
Hasil:
5360 dari 1000000 teka-teki dapat dipecahkan. Total kita membutuhkan 69519 blok. Jumlah blok bervariasi dari 6 blok hingga 18 blok. Teka-teki tersulit membutuhkan waktu sekitar 1 detik untuk dipecahkan. Ini teka-teki dengan benih
"347177"
, yang terlihat sepertidan memiliki solusi optimal dengan 18 kubus. Berikut ini adalah beberapa dari atas untuk masing-masing lapisan:
Total waktu berjalan untuk semua kasus uji adalah sekitar 90 detik. Saya menggunakan PyPy untuk menjalankan program saya. CPython (juru bahasa Python default) sedikit lebih lambat, tetapi juga memecahkan semua teka-teki hanya dalam 7 menit.
Anda dapat menemukan output lengkap di sini : Outputnya cukup jelas. Misalnya output untuk puzzle di atas adalah:
sumber
5360 kasus diselesaikan dengan 69519 blok; 923 byte
Ini juga optimal. Panggil dengan array yang dan nol. Melempar
NullPointerException
input yang tidak valid. Beberapa efisiensi dikorbankan untuk golf itu. Itu masih selesai dalam waktu yang wajar untuk semua input uji 1000000.Strategi:
Saya sebenarnya cukup sering memainkan puzzle ini ketika saya berumur 10 tahun. Ini menggunakan pendekatan saya.
Langkah 1:
Bentuk kubus dengan blok terbanyak yang sesuai dengan tampilan yang diberikan.
Langkah 2:
Buat daftar potongan yang bisa dilepas. (Setiap bagian dengan yang memiliki bagian lain pada baris dalam, kolom dalam, dan balok dalam.)
Langkah 3:
Uji setiap cara yang mungkin untuk menyimpan atau menghapus setiap bagian yang dapat dilepas. (Melalui brute-force rekursif dengan pemangkasan.)
Langkah 4:
Simpan kubus valid terbaik.
Tidak Disatukan:
Program lengkap:
sumber