Isi baris, kolom, dan diagonal kotak NxN dengan 1 hingga N


26

Tugas

Diberikan input N, hasilkan dan hasilkan kisi NxN di mana setiap baris, kolom, dan kedua diagonal berisi angka 1 hingga N(atau 0 hinggaN −1 jika itu lebih mudah).

Memasukkan

Inputnya adalah bilangan bulat positif N. Ini mewakili jumlah kolom dan baris dalam kisi. Untuk masalah ini, Anda dapat menganggap Nukurannya masuk akal, 4 ≤ N ≤ 8atau (1 ≤ N ≤ 8 jika Anda memilih bonus di bawah ini).

Keluaran

Outputnya adalah N× Ngrid. Dalam kisi, setiap baris hanya berisi angka 1 hingga N, setiap kolom hanya berisi angka 1 hingga N, dan dua diagonal panjang N(satu dari (0,0)ke (N-1,N-1)dan satu dari (0,N-1)ke (N-1, 0)) hanya berisi angka 1 hingga N. Anda dapat menggunakan angka 0 hingga N−1. Untuk setiapN , ada banyak solusi yang mungkin, Anda hanya perlu mencetak yang pertama yang Anda temukan. Anda tidak perlu mencetak spasi di antara angka-angka.

Kendala

Kode Anda harus dapat menghasilkan hasil secara berulang N >= 7. Artinya, jika Anda benar-benar dapat menjalankan dan mendapatkan solusi N = 7dari kode Anda setiap kali, Anda baik. Dalam hal batas absolut, kode Anda harus dapat diselesaikan N = 7dalam waktu kurang dari 10 menit setiap kali Anda menjalankannya (yaitu, jika Anda bergantung pada angka acak, untuk kasus terburuk, kode Anda masih harus selesai di bawah 10 menit untuk N = 7) .

Contohnya

  • Memasukkan: 4

    Satu kemungkinan keluaran:

    1 2 3 4
    3 4 1 2
    4 3 2 1
    2 1 4 3
    
  • Memasukkan: 5

    Satu kemungkinan keluaran:

    1 2 3 4 5
    5 3 1 2 4
    2 5 4 3 1
    4 1 2 5 3
    3 4 5 1 2
    
  • Memasukkan: 8

    Satu kemungkinan keluaran:

    1 2 3 4 5 6 7 8
    2 3 1 5 4 8 6 7
    4 1 2 3 7 5 8 6
    6 4 7 8 1 2 3 5
    7 5 8 2 6 3 4 1
    5 8 4 6 2 7 1 3
    8 7 6 1 3 4 5 2
    3 6 5 7 8 1 2 4
    

Mencetak gol

Ini adalah , jadi kode terpendek dalam byte menang, dengan satu pengecualian. Untuk input N = 2, 3tidak ada solusi yang valid. Jika kode Anda dapat menangani ini (jalankan sampai selesai tanpa mengeluarkan apa pun untuk kasus ini, atau mengeluarkan string kosong), dan masih menangani N = 1(menghasilkan 1untuk itu), ambil 20% dari jumlah byte Anda.


1
Terkait , tetapi kotak seperti itu tidak akan berfungsi di sini karena persyaratan diagonal.
xnor

Saya suka tantangan ini, tetapi saya tidak tahu algoritma untuk nilai genap N. Kode JavaScript ini berfungsi N = 1, 5 or 7meskipun jika itu membantu siapa pun:for(o="",y=N;y--;o+="\n")for(x=N;x--;)o+=(((N-y)*2+x)%N)+1
user81655

Sangat terkait, kemungkinan duplikat: codegolf.stackexchange.com/q/47846/15599
Level River St

@steveverrill Itu bukan kode golf.
randomra

1
Mungkin Anda harus lebih eksplisit tentang N = 1kasus ini: jawaban yang bertujuan untuk bonus harus dikembalikan 1, bukan string kosong.
Lynn

Jawaban:


3

Python 3, 275 260 Bytes * 0.8 = 220 208 Bytes

Pendekatan rekursif / mundur. Radalah fungsi rekursif, ladalah kolom, wadalah roW, Kadalah entri berikutnya.

Saya memilih untuk meletakkannya di array 1d dan cukup mencetaknya di akhir untuk membuat indeks lebih sederhana.

r=range
n=(int)(input())
def R(A,I):
 l=I%n;w=I//n
 if I==n*n:[print(A[i*n:i*n+n])for i in r(n)];exit()
 for K in r(n):
  if all([all([A[i*n+l]!=K,w!=l or A[i+n*i]!=K,w!=n-1-l or A[n*i+n-i-1]!=K])for i in r(w)]+[A[w*n+i]!=K for i in r(l)]):R(A+[K],I+1)
R([],0)

Versi tidak disatukan:

def Recurse(A,I,n):
 column=I%n
 row=I//n
 if I==n*n:
     [print(*A[i*n:i*n+n])for i in range(n)] # output
     exit() #end recursion
 for K in range(n):
    # try every possibility. Test if they satisfy the constraints:
    # if so, move the index on. If none of them do, we'll return None.
    # if a child returns None, we'll move onto the next potential child:
    # if all of them fail it will backtrack to the next level.
    if all([
        all([
            A[i*n+column]!=K, # column constraint
            row!=column or A[i+n*i]!=K, # diagonal constraint
            row!=n-1-column or A[n*i+n-i-1]!=K # antidiagonal constraint
            ]) for i in range(row)
        ]+[
            A[row*n+i]!=K for i in range(column) # row constraint
            ]):
        Recurse(A+[K],I+1,n)

Recurse([],0,(int)(input()))

22

Funciton , tidak kompetitif

MEMPERBARUI! Peningkatan kinerja besar-besaran! n = 7 sekarang selesai dalam waktu kurang dari 10 menit! Lihat penjelasan di bawah!

Ini menyenangkan untuk ditulis. Ini adalah brute-force solver untuk masalah ini yang ditulis dalam Funciton. Beberapa factoids:

  • Ia menerima integer pada STDIN. Setiap spasi putih asing memecahnya, termasuk baris baru setelah integer.
  • Ia menggunakan angka 0 sampai n - 1 (bukan 1 ke n ).
  • Itu mengisi grid "mundur", sehingga Anda mendapatkan solusi di mana baris bawah membaca 3 2 1 0daripada di mana baris atas dibaca 0 1 2 3.
  • Ini menghasilkan dengan benar 0(satu-satunya solusi) untuk n = 1.
  • Output kosong untuk n = 2 dan n = 3.
  • Ketika dikompilasi ke exe, dibutuhkan sekitar 8¼ menit untuk n = 7 (sekitar satu jam sebelum peningkatan kinerja). Tanpa mengkompilasi (menggunakan interpreter) dibutuhkan sekitar 1,5 kali lebih lama, jadi menggunakan kompiler sepadan.
  • Sebagai tonggak pribadi, ini adalah pertama kalinya saya menulis seluruh program Funciton tanpa terlebih dahulu menulis program dalam bahasa pseudocode. Saya menulisnya di C # sebenarnya pertama meskipun.
  • (Namun, ini bukan pertama kalinya saya melakukan perubahan untuk secara masif meningkatkan kinerja sesuatu di Funciton. Pertama kali saya melakukan itu dalam fungsi faktorial. Menukar urutan operan perkalian membuat perbedaan besar karena cara kerja algoritma multiplikasi . Jika Anda penasaran.)

Tanpa basa-basi:

            ┌────────────────────────────────────┐           ┌─────────────────┐
            │                                  ┌─┴─╖ ╓───╖ ┌─┴─╖   ┌──────┐    │
            │                    ┌─────────────┤ · ╟─╢ Ӂ ╟─┤ · ╟───┤      │    │
            │                    │             ╘═╤═╝ ╙─┬─╜ ╘═╤═╝ ┌─┴─╖    │    │
            │                    │               └─────┴─────┘   │ ♯ ║    │    │
            │                  ┌─┴─╖                             ╘═╤═╝    │    │
            │     ┌────────────┤ · ╟───────────────────────────────┴───┐  │    │
          ┌─┴─╖ ┌─┴─╖   ┌────╖ ╘═╤═╝ ┌──────────┐         ┌────────┐ ┌─┴─╖│    │
          │ ♭ ║ │ × ╟───┤ >> ╟───┴───┘        ┌─┴─╖       │ ┌────╖ └─┤ · ╟┴┐   │
          ╘═╤═╝ ╘═╤═╝   ╘══╤═╝          ┌─────┤ · ╟───────┴─┤ << ╟─┐ ╘═╤═╝ │   │
    ┌───────┴─────┘ ┌────╖ │            │     ╘═╤═╝         ╘══╤═╝ │   │   │   │
    │     ┌─────────┤ >> ╟─┘            │       └───────┐      │   │   │   │   │
    │     │         ╘══╤═╝            ┌─┴─╖   ╔═══╗   ┌─┴─╖ ┌┐ │   │ ┌─┴─╖ │   │
    │     │           ┌┴┐     ┌───────┤ ♫ ║ ┌─╢ 0 ║ ┌─┤ · ╟─┤├─┤   ├─┤ Ӝ ║ │   │
    │     │   ╔═══╗   └┬┘     │       ╘═╤═╝ │ ╚═╤═╝ │ ╘═╤═╝ └┘ │   │ ╘═╤═╝ │   │
    │     │   ║ 1 ╟───┬┘    ┌─┴─╖       └───┘ ┌─┴─╖ │   │      │   │   │ ┌─┴─╖ │
    │     │   ╚═══╝ ┌─┴─╖   │ ɓ ╟─────────────┤ ? ╟─┘   │    ┌─┴─╖ │   ├─┤ · ╟─┴─┐
    │     ├─────────┤ · ╟─┐ ╘═╤═╝             ╘═╤═╝   ┌─┴────┤ + ╟─┘   │ ╘═╤═╝   │
  ┌─┴─╖ ┌─┴─╖       ╘═╤═╝ │ ╔═╧═╕ ╔═══╗ ┌───╖ ┌─┴─╖ ┌─┴─╖    ╘═══╝     │   │     │
┌─┤ · ╟─┤ · ╟───┐     └┐  └─╢   ├─╢ 0 ╟─┤ ⌑ ╟─┤ ? ╟─┤ · ╟──────────────┘   │     │
│ ╘═╤═╝ ╘═╤═╝   └───┐ ┌┴┐   ╚═╤═╛ ╚═╤═╝ ╘═══╝ ╘═╤═╝ ╘═╤═╝                  │     │
│   │   ┌─┴─╖ ┌───╖ │ └┬┘   ┌─┴─╖ ┌─┘           │     │                    │     │
│ ┌─┴───┤ · ╟─┤ Җ ╟─┘  └────┤ ? ╟─┴─┐   ┌─────────────┘                    │     │
│ │     ╘═╤═╝ ╘═╤═╝         ╘═╤═╝   │   │╔════╗╔════╗                      │     │
│ │       │  ┌──┴─╖ ┌┐   ┌┐ ┌─┴─╖ ┌─┴─╖ │║ 10 ║║ 32 ║    ┌─────────────────┘     │
│ │       │  │ << ╟─┤├─┬─┤├─┤ · ╟─┤ · ╟─┘╚══╤═╝╚╤═══╝ ┌──┴──┐                    │
│ │       │  ╘══╤═╝ └┘ │ └┘ ╘═╤═╝ ╘═╤═╝     │ ┌─┴─╖ ┌─┴─╖ ┌─┴─╖                  │
│ │     ┌─┴─╖ ┌─┴─╖  ┌─┴─╖  ┌─┴─╖ ╔═╧═╕     └─┤ ? ╟─┤ · ╟─┤ % ║                  │
│ └─────┤ · ╟─┤ · ╟──┤ Ӂ ╟──┤ ɱ ╟─╢   ├───┐   ╘═╤═╝ ╘═╤═╝ ╘═╤═╝                  │
│       ╘═╤═╝ ╘═╤═╝  ╘═╤═╝  ╘═══╝ ╚═╤═╛ ┌─┴─╖ ┌─┴─╖   │     └────────────────────┘
│         └─────┤      │            └───┤ ‼ ╟─┤ ‼ ║   │        ┌──────┐
│               │      │                ╘═══╝ ╘═╤═╝   │        │ ┌────┴────╖
│               │      │                      ┌─┴─╖   │        │ │ str→int ║
│               │      └──────────────────────┤ · ╟───┴─┐      │ ╘════╤════╝
│               │          ┌─────────╖        ╘═╤═╝     │    ╔═╧═╗ ┌──┴──┐
│               └──────────┤ int→str ╟──────────┘       │    ║   ║ │ ┌───┴───┐
│                          ╘═════════╝                  │    ╚═══╝ │ │ ┌───╖ │
└───────────────────────────────────────────────────────┘          │ └─┤ × ╟─┘
           ┌──────────────┐                                  ╔═══╗ │   ╘═╤═╝
╔════╗     │ ╓───╖ ┌───╖  │                              ┌───╢ 0 ║ │   ┌─┴─╖ ╔═══╗
║ −1 ║     └─╢ Ӝ ╟─┤ × ╟──┴──────┐                       │   ╚═╤═╝ └───┤ Ӂ ╟─╢ 0 ║
╚═╤══╝       ╙───╜ ╘═╤═╝         │                       │   ┌─┴─╖     ╘═╤═╝ ╚═══╝
┌─┴──╖ ┌┐ ┌───╖ ┌┐ ┌─┴──╖ ╔════╗ │                       │ ┌─┤   ╟───────┴───────┐
│ << ╟─┤├─┤ ÷ ╟─┤├─┤ << ║ ║ −1 ║ │                       │ │ └─┬─╜ ┌─┐ ┌─────┐   │
╘═╤══╝ └┘ ╘═╤═╝ └┘ ╘═╤══╝ ╚═╤══╝ │                       │ │   └───┴─┘ │   ┌─┴─╖ │
  │         └─┘      └──────┘    │                       │ └───────────┘ ┌─┤ ? ╟─┘
  └──────────────────────────────┘         ╓───╖         └───────────────┘ ╘═╤═╝
                               ┌───────────╢ Җ ╟────────────┐                │
      ┌────────────────────────┴───┐       ╙───╜            │
      │                          ┌─┴────────────────────┐ ┌─┴─╖
    ┌─┴─╖                      ┌─┴─╖                  ┌─┴─┤ · ╟──────────────────┐
    │ ♯ ║ ┌────────────────────┤ · ╟───────┐          │   ╘═╤═╝                  │
    ╘═╤═╝ │                    ╘═╤═╝       │          │     │              ┌───╖ │
┌─────┴───┘    ┌─────────────────┴─┐   ┌───┴───┐    ┌─┴─╖ ┌─┴─╖          ┌─┤ × ╟─┴─┐
│              │                 ┌─┴─╖ │   ┌───┴────┤ · ╟─┤ · ╟──────────┤ ╘═╤═╝   │
│              │ ┌───╖ ┌───╖  ┌──┤ · ╟─┘ ┌─┴─┐      ╘═╤═╝ ╘═╤═╝        ┌─┴─╖ │     │
│         ┌────┴─┤ ♭ ╟─┤ × ╟──┘  ╘═╤═╝   │ ┌─┴─╖ ┌───╖└┐ ┌──┴─╖      ┌─┤ · ╟─┘     │
│         │      ╘═══╝ ╘═╤═╝ ┌───╖ │     │ │ × ╟─┤ Ӝ ╟─┴─┤ ÷% ╟─┐    │ ╘═╤═╝ ┌───╖ │
│   ┌─────┴───┐     ┌────┴───┤ Ӝ ╟─┴─┐   │ ╘═╤═╝ ╘═╤═╝   ╘══╤═╝ │    │   └───┤ Ӝ ╟─┘
│ ┌─┴─╖ ┌───╖ │     │ ┌────╖ ╘═╤═╝   │   └───┘   ┌─┴─╖      │   │    └────┐  ╘═╤═╝
│ │ × ╟─┤ Ӝ ╟─┘     └─┤ << ╟───┘   ┌─┴─╖ ┌───────┤ · ╟───┐  │ ┌─┴─╖ ┌───╖ │    │
│ ╘═╤═╝ ╘═╤═╝         ╘══╤═╝   ┌───┤ + ║ │       ╘═╤═╝   ├──┴─┤ · ╟─┤ × ╟─┘    │
└───┤     └────┐ ╔═══╗ ┌─┴─╖ ┌─┴─╖ ╘═╤═╝ │ ╔═══╗ ┌─┴─╖ ┌─┴─╖  ╘═╤═╝ ╘═╤═╝      │
  ┌─┴─╖ ┌────╖ │ ║ 0 ╟─┤ ? ╟─┤ = ║  ┌┴┐  │ ║ 0 ╟─┤ ? ╟─┤ = ║    │     │ ┌────╖ │
  │ × ╟─┤ << ╟─┘ ╚═══╝ ╘═╤═╝ ╘═╤═╝  └┬┘  │ ╚═══╝ ╘═╤═╝ ╘═╤═╝    │     └─┤ << ╟─┘
  ╘═╤═╝ ╘═╤══╝ ┌┐     ┌┐ │     │     └───┘       ┌─┴─╖   ├──────┘       ╘═╤══╝
    │     └────┤├──┬──┤├─┘     ├─────────────────┤ · ╟───┘                │
    │          └┘┌─┴─╖└┘       │     ┌┐   ┌┐     ╘═╤═╝ ┌┐   ┌┐            │
    └────────────┤ · ╟─────────┘   ┌─┤├─┬─┤├─┐     └───┤├─┬─┤├────────────┘
                 ╘═╤═╝             │ └┘ │ └┘ │         └┘ │ └┘
                   └───────────────┘    │    └────────────┘

Penjelasan dari versi pertama

Versi pertama membutuhkan waktu sekitar satu jam untuk menyelesaikan n = 7. Berikut ini sebagian besar menjelaskan bagaimana versi lambat ini bekerja. Di bagian bawah saya akan menjelaskan perubahan apa yang saya buat untuk mendapatkannya di bawah 10 menit.

Tamasya menjadi bit

Program ini membutuhkan bit. Perlu banyak bit, dan membutuhkannya di semua tempat yang tepat. Pemrogram Funciton berpengalaman sudah tahu bahwa jika Anda membutuhkan n bit, Anda dapat menggunakan rumus

2 ^ n-1

yang dalam Funciton dapat dinyatakan sebagai

(1 << n) - 1

Ketika melakukan optimasi kinerja saya, terpikir oleh saya bahwa saya dapat menghitung nilai yang sama lebih cepat menggunakan rumus ini:

¬ (−1 << n)

Saya harap Anda memaafkan saya bahwa saya tidak memperbarui semua grafik persamaan dalam posting ini.

Sekarang, katakanlah Anda tidak ingin blok bit yang berdekatan; sebenarnya, Anda ingin n bit secara berkala setiap k -th bit, seperti:

                                 LSB
                                  ↓
00000010000001000000100000010000001
                            └──┬──┘
                               k

Formula untuk ini cukup mudah setelah Anda mengetahuinya:

((1 << nk) - 1) / ((1 << k) - 1)

Dalam kode, fungsi tersebut Ӝmengambil nilai n dan k dan menghitung rumus ini.

Melacak nomor yang digunakan

Ada n ² angka dalam kisi terakhir, dan setiap angka dapat berupa n nilai yang mungkin. Untuk melacak nomor mana yang diizinkan dalam setiap sel, kami mempertahankan nomor yang terdiri dari n ³ bit, di mana bit diatur untuk menunjukkan bahwa nilai tertentu diambil. Awalnya angka ini adalah 0, jelas.

Algoritma dimulai di sudut kanan bawah. Setelah "menebak" angka pertama adalah 0, kita perlu melacak fakta bahwa 0 tidak lagi diizinkan di sel mana pun di sepanjang baris, kolom, dan diagonal yang sama:

LSB                               (example n=5)
 ↓
 10000 00000 00000 00000 10000
 00000 10000 00000 00000 10000
 00000 00000 10000 00000 10000
 00000 00000 00000 10000 10000
 10000 10000 10000 10000 10000
                             ↑
                            MSB

Untuk tujuan ini, kami menghitung empat nilai berikut:

  • Baris saat ini: Kami perlu n bit setiap n bit th (satu per sel), dan kemudian beralih ke baris saat ini r , mengingat setiap baris berisi n ² bit:

    ((1 << n²) −1) / ((1 << n) −1) << n²r

  • Kolom saat ini: Kami membutuhkan n bit setiap n ²-th bit (satu per baris), dan kemudian menggesernya ke kolom saat ini c , mengingat setiap kolom berisi n bit:

    ((1 << n³) −1) / ((1 << n²) −1) << n²r

  • Maju diagonal: Kami membutuhkan n bit setiap ... (apakah Anda memperhatikan? Cepat, cari tahu!) ... n ( n +1)-bit (dilakukan dengan baik!), Tetapi hanya jika kami benar-benar aktif maju diagonal:

    ((1 << n² (n + 1)) - 1) / ((1 << n (n + 1)) - 1) jika c = r

  • Backward diagonal: Dua hal di sini. Pertama, bagaimana kita tahu kalau kita berada di diagonal mundur? Secara matematis, kondisinya adalah c = ( n - 1) - r , yang sama dengan c = n + (- r - 1). Hei, apakah itu mengingatkanmu pada sesuatu? Itu benar, itu pelengkap dua, jadi kita bisa menggunakan negasi bitwise (sangat efisien di Funciton) alih-alih pengurangan. Kedua, rumus di atas mengasumsikan bahwa kita ingin bit yang paling tidak signifikan untuk diatur, tetapi di diagonal mundur kita tidak, jadi kita harus menggesernya dengan ... apakah Anda tahu? ... Itu benar, n ( n - 1).

    ((1 << n² (n-1)) - 1) / ((1 << n (n-1)) - 1) << n (n-1) jika c = n + ¬r

    Ini juga satu-satunya di mana kita berpotensi membagi dengan 0 jika n = 1. Namun, Funciton tidak peduli. 0 ÷ 0 hanya 0, tahukah Anda?

Dalam kode, fungsi Җ(yang terbawah) mengambil n dan indeks (dari mana ia menghitung r dan c berdasarkan pembagian dan sisanya), menghitung keempat nilai ini dan ormenyatukannya.

Algoritma brute-force

Algoritma brute-force diimplementasikan oleh Ӂ(fungsi di atas). Dibutuhkan n (ukuran kisi), indeks (di mana dalam kisi kita saat ini menempatkan nomor), dan diambil (angka dengan n ³ bit memberi tahu kita nomor mana yang masih bisa kita tempatkan di setiap sel).

Fungsi ini mengembalikan urutan string. Setiap string adalah solusi lengkap untuk grid. Ini adalah pemecah yang lengkap; itu akan mengembalikan semua solusi jika Anda membiarkannya, tetapi mengembalikannya sebagai urutan malas yang dievaluasi.

  • Jika indeks telah mencapai 0, kami telah berhasil mengisi seluruh grid, jadi kami mengembalikan urutan berisi string kosong (solusi tunggal yang tidak mencakup sel). String kosong adalah 0, dan kami menggunakan fungsi pustaka untuk mengubahnya menjadi urutan elemen tunggal.

  • Pemeriksaan yang dijelaskan dalam peningkatan kinerja di bawah ini terjadi di sini.

  • Jika indeks belum mencapai 0, kami menurunkannya dengan 1 untuk mendapatkan indeks di mana sekarang kita perlu menempatkan nomor (sebut itu ix ).

    Kami menggunakan untuk menghasilkan urutan malas yang berisi nilai dari 0 hingga n - 1.

    Kemudian kami menggunakan ɓ(ikatan monadik) dengan lambda yang melakukan hal berikut secara berurutan:

    • Pertama-tama lihat bit yang relevan yang diambil untuk memutuskan apakah nomor tersebut valid di sini atau tidak. Kita dapat menempatkan nomor i jika dan hanya jika diambil & (1 << ( n × ix ) << i ) belum ditetapkan. Jika diatur, kembali 0(urutan kosong).
    • Gunakan Җuntuk menghitung bit yang sesuai dengan baris, kolom, dan diagonal saat ini. Bergeser dengan saya dan kemudian oritu ke diambil .
    • Panggilan secara rekursif Ӂuntuk mengambil semua solusi untuk sel yang tersisa, meneruskannya dengan yang baru diambil dan ix yang dikurangi . Ini mengembalikan urutan string tidak lengkap; setiap string memiliki karakter ix (kotak diisi hingga indeks ix ).
    • Gunakan ɱ(peta) untuk pergi melalui solusi yang ditemukan dan gunakan untuk menggabungkan saya ke akhir masing-masing. Tambahkan baris baru jika indeks adalah kelipatan n , jika tidak spasi.

Menghasilkan hasilnya

Panggilan program utama Ӂ(brute forcer) dengan n , index = n ² (ingat kita mengisi grid mundur) dan mengambil = 0 (awalnya tidak ada yang diambil). Jika hasil dari ini adalah urutan kosong (tidak ada solusi yang ditemukan), output string kosong. Kalau tidak, output string pertama dalam urutan. Perhatikan bahwa ini berarti ia hanya akan mengevaluasi elemen pertama dari urutan, itulah sebabnya pemecah tidak melanjutkan sampai ia menemukan semua solusi.

Peningkatan performa

(Bagi mereka yang sudah membaca versi lama dari penjelasan: program tidak lagi menghasilkan urutan urutan yang perlu secara terpisah diubah menjadi string untuk output; itu hanya menghasilkan urutan string secara langsung. Saya telah mengedit penjelasan sesuai Tapi itu bukan peningkatan utama. Ini dia.)

Di komputer saya, exe yang dikompilasi dari versi pertama hanya membutuhkan waktu 1 jam untuk menyelesaikan n = 7. Ini tidak dalam batas waktu yang diberikan 10 menit, jadi saya tidak beristirahat. (Yah, sebenarnya, alasan aku tidak beristirahat adalah karena aku punya ide tentang cara mempercepatnya secara masif.)

Algoritme seperti dijelaskan di atas menghentikan pencarian dan backtracks setiap kali menemukan sel di mana semua bit dalam jumlah yang diambil ditetapkan, menunjukkan bahwa tidak ada yang dapat dimasukkan ke dalam sel ini.

Namun, algoritme akan terus mengisi grid dengan sia-sia hingga ke sel tempat semua bit diatur. Akan jauh lebih cepat jika bisa berhenti begitu setiap sel yang belum diisi sudah memiliki semua bit yang ditetapkan, yang sudah menunjukkan bahwa kita tidak akan pernah bisa menyelesaikan sisa grid tidak peduli berapa nomor yang kita masukkan saya t. Tetapi bagaimana Anda secara efisien memeriksa apakah ada sel yang memiliki n bit yang diset tanpa melalui semuanya?

Caranya dimulai dengan menambahkan satu bit per sel ke nomor yang diambil . Alih-alih apa yang ditunjukkan di atas, sekarang tampilannya seperti ini:

LSB                               (example n=5)
 ↓
 10000 0 00000 0 00000 0 00000 0 10000 0
 00000 0 10000 0 00000 0 00000 0 10000 0
 00000 0 00000 0 10000 0 00000 0 10000 0
 00000 0 00000 0 00000 0 10000 0 10000 0
 10000 0 10000 0 10000 0 10000 0 10000 0
                                       ↑
                                      MSB

Alih-alih n ³, sekarang ada n ² ( n +1) bit dalam angka ini. Fungsi yang mengisi baris / kolom / diagonal saat ini telah diubah sesuai (sebenarnya, sepenuhnya ditulis ulang untuk jujur). Fungsi itu masih akan mengisi hanya n bit per sel, jadi bit tambahan yang baru saja kita tambahkan akan selalu 0.

Sekarang, katakanlah kita setengah jalan dalam perhitungan, kita baru saja menempatkan sebuah 1di sel tengah, dan jumlah yang diambil terlihat seperti ini:

                 current
LSB              column           (example n=5)
 ↓                 ↓
 11111 0 10010 0 01101 0 11100 0 11101 0
 00011 0 11110 0 01101 0 11101 0 11100 0
 11111 0 11110 0[11101 0]11100 0 11100 0    ← current row
 11111 0 11111 0 11111 0 11111 0 11111 0
 11111 0 11111 0 11111 0 11111 0 11111 0
                                       ↑
                                      MSB

Seperti yang Anda lihat, sel kiri atas (indeks 0) dan sel kiri tengah (indeks 10) sekarang tidak mungkin. Bagaimana kita menentukan ini dengan paling efisien?

Pertimbangkan angka di mana bit ke-0 dari setiap sel diatur, tetapi hanya sampai indeks saat ini. Angka seperti itu mudah dihitung menggunakan rumus yang sudah dikenal:

((1 << (n +1) i) - 1) / ((1 << (n +1)) - 1)

Apa yang akan kita dapatkan jika kita menambahkan dua angka ini bersama?

LSB                                               LSB
 ↓                                                 ↓
 11111 0 10010 0 01101 0 11100 0 11101 0           10000 0 10000 0 10000 0 10000 0 10000 0        ╓───╖
 00011 0 11110 0 01101 0 11101 0 11100 0     ║     10000 0 10000 0 10000 0 10000 0 10000 0            ║
 11111 0 11110 0 11101 0 11100 0 11100 0  ═══╬═══  10000 0 10000 0 00000 0 00000 0 00000 0  ═════   ╓─╜
 11111 0 11111 0 11111 0 11111 0 11111 0     ║     00000 0 00000 0 00000 0 00000 0 00000 0  ═════   ╨
 11111 0 11111 0 11111 0 11111 0 11111 0           00000 0 00000 0 00000 0 00000 0 00000 0          o
                                       ↑                                                 ↑
                                      MSB                                               MSB

Hasilnya adalah:

             OMG
              ↓
        00000[1]01010 0 11101 0 00010 0 00011 0
        10011 0 00001 0 11101 0 00011 0 00010 0
═════   00000[1]00001 0 00011 0 11100 0 11100 0
═════   11111 0 11111 0 11111 0 11111 0 11111 0
        11111 0 11111 0 11111 0 11111 0 11111 0

Seperti yang Anda lihat, penambahan melimpah ke bit ekstra yang kami tambahkan, tetapi hanya jika semua bit untuk sel itu ditetapkan! Karenanya, yang harus dilakukan hanyalah menutupi bit-bit itu (rumus yang sama seperti di atas, tetapi << n menutup ) dan periksa apakah hasilnya 0:

00000[1]01010 0 11101 0 00010 0 00011 0    ╓╖    00000 1 00000 1 00000 1 00000 1 00000 1         ╓─╖ ╓───╖
10011 0 00001 0 11101 0 00011 0 00010 0   ╓╜╙╖   00000 1 00000 1 00000 1 00000 1 00000 1        ╓╜ ╙╖    ║
00000[1]00001 0 00011 0 11100 0 11100 0   ╙╥╥╜   00000 1 00000 1 00000 0 00000 0 00000 0  ═════ ║   ║  ╓─╜
11111 0 11111 0 11111 0 11111 0 11111 0   ╓╜╙╥╜  00000 0 00000 0 00000 0 00000 0 00000 0  ═════ ╙╖ ╓╜  ╨
11111 0 11111 0 11111 0 11111 0 11111 0   ╙──╨─  00000 0 00000 0 00000 0 00000 0 00000 0         ╙─╜   o

Jika bukan nol, kisi tidak mungkin dan kita bisa berhenti.

  • Tangkapan layar menampilkan solusi dan waktu berjalan untuk n = 4 hingga 7.

3
APAAN KUDUS. Kawan, itu mengesankan.
Deusovi

1
Saya komentar kedua @ Deusovi, terima kasih telah mengerahkan banyak upaya dalam hal ini
hargasinski

7

Haskell, 790 * 0,80 = 632 byte

import Data.List
import Control.Monad
import Data.Array
s r=let{h as bs=[(a,b)|a<-as,b<-bs];(&)m k=(\(Just x)->x)$lookup k m;j=Just;n=Nothing;c=[1..r];q=delete;u=h[1..r]c;o=[(s,[u |u<-[h[1..r][c]|c<-c]++[h[r]c|r<-[1..r]]++[zip[1..r][1..r],zip[1..r][r,r-1..1]],s`elem`u])|s<-u];k=foldr(>=>)j;a p d g0=k[t p d2|d2<-q d(g0!p)]g0;t p d g0|not(d`elem`(g0!p))=j g0|[]<-v=n|[d2]<-v=k[t s2 d2|s2<-[(s,delete s$nub(concat(o&s)))|s<-u]&p]g1|True=k[l[s|s<-u,not(d`elem`v)]|u<-o&p]g1 where{v=q d(g0!p);g1=g0//[(p,v)];l[]_=n;l[d3]g=a d3 d g;l _ r=j r};w g0|and[case g0!s of{[_]->True;_->False}|s<-u]=j g0|True=msum[a s' d g0>>=w|d<-g0!s']where(_,s')=minimumBy(\(a,_)(b,_)->compare a b)[(l,s)|s<-u,let v=g0!s;l=length v,l>1]}in fmap(fmap(\[x]->x))$w$array((1,1),(r,r))[((i,j),[1..r])|i<-[1..r],j<-[1..r]]

Saya perhatikan masalah ini sangat mirip dengan sudoku. Saya ingat pemecah sudoku tua yang saya tulis di Haskell berdasarkan yang lain ini di Python. Ini adalah posting atau usaha golf kode pertama saya.

Ini memenuhi bonus karena ia mengembalikan Nothinguntuk n=2,3dan Just <result>untuk n>=4, di mana <result>adalah array 2D nilai integral.

Lihat di sini untuk penerjemah online. Kode itu sebenarnya lebih panjang dari yang ada di pos karena penerjemah online memiliki persyaratan yang lebih ketat untuk apa yang membentuk program yang lengkap (aturan mengatakan pengiriman dapat menjadi fungsi). Kiriman ini mengambil input sebagai argumen fungsi.


1
Beberapa tip cepat: a) Anda tentukan c=[1..r], sehingga Anda dapat menggunakannya di dalam odan w. b) minimumBy(\(a,_)(b,_)->compare a b)[...]adalah head$sortOn fst[...]. c) vdalam v=g0!shanya digunakan sekali, jadi jangan menentukan sama sekali: l=length$g0!s. d) Anda masih memiliki beberapa nama parameter dua huruf. e) ganti Truedengan 1<2dan Falsedengan 2<1. f) and[case g0!s of{[_]->True;_->False}|s<-u]adalah all((==1).length.(g0!))u.
nimi

Cepat tips, bagian II: g) (&)m k=dapat didefinisikan infiks: m&k=. h) not(dElem (g0!p))adalah notElem d$g0!p. i) concat(...)adalah id=<<(...). j) menggunakan operator infiks untuk h, mis as%bs=.
nimi

3
Kiat meta cepat: Anda dapat membatasi kode yang memiliki backticks di dalamnya dengan benar menggunakan double backticks ​``like`this``​!
Lynn

4

Pyth, 41 byte

#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K
#                                      ;   # while(True)
 Km.SQQ                                    # K = random QxQ 2d list
       I                               ;   # if ...
        .A                                 # all of...
          m                          Q     # map(range(Q))...
                +                          # concat
                 .TK                       # transpose K
                    .Tm,@@Kdd@@Kt-Qdd      # diagonals of K
                      m             d      # map(range(d))
                       ,                   # 2-elem list of...
                        @@Kdd              # K[n][n]
                             @@Kt-Qd       # and K[len(K)-n-1][n]
                    .T                     # transpose
           qQl{d                           # subarrays have no dups...
                                      B;   # ... then, break
                                        K  # output final result

Brute force ftw!

Karena ini pada dasarnya terus mencoba acak acak hingga berfungsi (ya, itu terus mencoba n * [shuffle(range(n))]), butuh waktu yang sangat, sangat lama. Berikut ini beberapa uji coba untuk memberi Anda gambaran tentang berapa lama waktu yang dibutuhkan:

llama@llama:~$ time echo 4 | pyth <(echo '#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K')               
[[2, 1, 0, 3], [0, 3, 2, 1], [3, 0, 1, 2], [1, 2, 3, 0]]
echo 4  0.00s user 0.00s system 0% cpu 0.001 total
pyth <(echo '#Km.SQQI.AmqQl{d+.TK.Tm,@@Kdd@@Kt-QddQB;K')  0.38s user 0.00s system 96% cpu 0.397 total

Itu hanya 4x4, dan berjalan dalam waktu kurang dari setengah detik. Saya sebenarnya curang karena ini adalah yang terbaik dari beberapa cobaan — kebanyakan dari mereka mengambil satu atau dua detik.

Saya belum mendapatkan waktu pada 5x5 (berlari sampai selesai sekali, tapi itu dalam REPL dan saya tidak menghitung waktu itu).

Perhatikan bahwa aturan untuk batas waktu hanya diedit ke pertanyaan setelah jawaban ini diposting.


Saya kira ini tidak bisa dilakukan 7x7 dalam sepuluh menit? ^^
Lynn

@Mauris Yah, kadang - kadang bisa ...;) Apakah itu persyaratan yang saya lewatkan? Saya tidak melihat apa pun yang menyebutkan batas waktu dalam pertanyaan.
Gagang Pintu

Saya melihatnya di komentar, (bukan komentar baru , 12 jam yang lalu)
edc65

Maaf tentang itu, saya tidak memikirkannya sampai seseorang menyebutkannya, saya akan mengedit tantangannya sekarang
hargasinski

1
+1 untuk seni abstrak ASCII dalam versi komentar Anda. :)
Ilmari Karonen

3

SWI-Prolog, 326 * 0,80 = 260,8 byte

:-use_module(library(clpfd)).
a(N):-l(N,R),m(l(N),R),append(R,V),V ins 1..N,transpose(R,C),d(0,R,D),maplist(reverse,R,S),d(0,S,E),m(m(all_distinct),[R,C,[D,E]]),m(label,R),m(p,R).
l(L,M):-length(M,L).
d(X,[H|R],[A|Z]):-nth0(X,H,A),Y is X+1,(R=[],Z=R;d(Y,R,Z)).
p([H|T]):-write(H),T=[],nl;write(' '),p(T).
m(A,B):-maplist(A,B).

Sunting: disimpan 16 byte berkat @Mat

Pemakaian

Hubungi a(5).juru bahasa Anda untuk N=5. Ini mengembalikan falseuntuk N=2atau N=3.

Karena menggunakan perpustakaan CLPFD ini bukan bruteforce murni. Program ini dapat menemukan solusi untukN=20 dalam waktu sekitar 15 detik di komputer saya.

Penjelasan + tidak dikumpulkan:

Ini pada dasarnya bekerja seperti pemecah Sudoku, kecuali bahwa batasan balok diganti dengan kendala diagonal.

:-use_module(library(clpfd)).      % Import Constraints library

a(N):-
    l(N,R),                        % R is a list of length N
    maplist(l(N),R),               % R contains sublists, each of length N
    append(R,V),                   
    V ins 1..N,                    % Each value in the matrix is between 1 and N
    maplist(all_distinct,R),       % Values must be different on each row
    transpose(R,C),
    maplist(all_distinct,C),       % Values must be different on each column
    d(0,R,D),
    maplist(reverse,R,S),          
    d(0,S,E),
    all_distinct(D),               % Values must be different on the diagonal
    all_distinct(E),               % Values must be different on the "anti"-diagonal
    maplist(label,R),              % Affects actual values to each element
    maplist(p,R).                  % Prints each row

l(L,M):-length(M,L).               % True if L is the length of M

d(X,[H|R],[A|Z]):-nth0(X,H,A),Y is X+1,(R=[],Z=R;d(Y,R,Z)). % True if the third argument is the diagonal of the second argument

p([H|T]):-write(H),T=[],nl;write(' '),p(T).  % Prints a row separated by spaces and followed by a new line

Sangat bagus! Anda dapat menyimpan byte dengan:maplist(maplist(all_distinct), [R,C,D,E])
mat

1
@ ah Terima kasih atas sarannya, menghemat 16 byte. Saya perlu menggunakan [R,C,[D,E]], karena Edan Ddaftar sederhana.
Fatalkan

Benar, solusi yang sangat bagus!
mat

2
@Fatalize Hanya untuk memberi tahu Anda, solusi Anda adalah yang paling mengesankan karena satu-satunya solusi yang dapat diselesaikanN=20
hargasinski

1
@ Terima kasih! Tapi itu sebagian besar disebabkan oleh pustaka CLPFD Prolog yang menakjubkan, yang mengangkat masalah besar seperti ini :)
Fatalize

2

CJam, 87 byte - bonus 20% = 69,6 byte

qi__"@I/l
ŤˏūȻ
܀ᅀ൹৽჈͚
㑢鴑慚菥洠㬝᚜
"N/=:i0+\,m!f=`1LL](4e<=

Hardcode jawabannya. Berisi beberapa unsintables. Bekerja N = 1melalui N = 8.

Pada dasarnya, setiap baris dalam string misterius berisi indeks ke dalam daftar permutasi range(N), dikodekan sebagai karakter Unicode.

=:i0+\,m!f=mengindeks ke dalam daftar permutasi, menambahkan 0 ke akhir daftar indeks terlebih dahulu, mewakili baris bawah 0 1 2 ... N-1. Sebab N < 4, array 2D yang dihasilkan adalah omong kosong.

`1LL]membuat daftar [N, pretty output, 1, "", ""]. Kemudian, (4e<=muncul elemen pertama dari daftar ini N,, dan ambil min(N, 4) % 4elemen th dari sisanya. Karena N >= 4, itulah outputnya, dan jika tidak, itu adalah output case khusus untuk tiga case pertama.

Coba di sini .


0

C ++, 672 * 0.80 645 * 0.80 = 516 byte

#include <iostream>
int **b,**x,**y,*d,*a,n;
#define R(i) for(i=0;i<n;i++){
#define E(e) e=new int[n];
int f(int c,int r) {int i=0,p=c-1;if(r>=n)return 1;if(c == n + 1)return f(1,r+1);R(i)int m=r==i,s=r+i==n-1;if(!b[r][i]&&!x[r][p]&&!(m&&d[p])&&!(s&&a[p])&&!y[i][p]){b[r][i]=c;x[r][p]=1;y[i][p]=1;if(m)d[p]=1;if(s)a[p]=1;if(f(c+1,r))return 1;b[r][i]=0;x[r][p]=0;y[i][p]=0;if(m)d[p]=0;if(s)a[p]=0;}}return 0;}
int main(){std::cin>>n;int i=0,j=0;b=new int*[n];x=new int*[n];y=new int*[n];E(d);E(a);R(i)E(b[i]);E(x[i]);E(y[i]); d[i]=0;a[i]=0;R(j)b[i][j]=0;x[i][j]=0;y[i][j]=0;}}if(f(1,0)){R(i)R(j)std::cout<<b[i][j];}std::cout<<std::endl;}}}

Cobalah online di sini

Karena beberapa jawaban telah diposting, saya pikir saya akan memposting versi golf dari kode yang saya gunakan untuk menghasilkan output untuk contoh. Ini adalah pertama kalinya saya menjawab a , jadi semua umpan balik disambut. :)

Penjelasan + tidak dikumpulkan:

Pada dasarnya, kode ini memaksa solusi. Itu dimulai di baris pertama, dengan 0. Dimulai di tempat pertama, jika tempat itu melewati semua cek, ia pindah ke nomor berikutnya. Jika mengisi baris, ia bergerak ke baris berikutnya. Jika dilakukan semua baris, itu berarti solusi telah ditemukan. Jika tempat tidak lulus semua cek, itu pindah ke tempat berikutnya. Jika dilakukan baris, maka backtracks, karena angka di salah satu baris sebelumnya mencegah kemungkinan solusi.

#include <iostream>

// global variables to save bytes on passing these are function arguments
int **b, // this will store the state of the board
    **x, // if x[i][j] is true, row i of b contains the number j
    **y, // if y[i][j] is true, column i of b contains the number j
    *d,  // if d[i] the main diagonal of b contains i
    *a,  // if a[i] the antidiagonal of a contains i
    n;

// preprocessor to save bytes on repeated statements
#define R(i) for(i=0;i<n;i++){
#define E(e) e=new int[n];

// Recursively looks for a solution 
// c - the current number to insert in row r
// r - the current row to fill
int f (int c, int r) {
        int i=0,p=c-1;
        if (r >= n) return 1;             // we are done
        if (c == n + 1) return f(1,r+1);  // this row is full, move to the next row
        R(i)                              // go through the positions in this row,
                                                                            // trying to fill them with c
                int m=r==i, s=r+i==n-1;   // check if this position (r,i) is on ones
                                                                            // of the diagonals
                // if this spot isn't filled, and the row (r), column (i) and diagonals
                // (if it's on the diagonal) doesn't contain the number, fill the spot
                if (!b[r][i] && !x[r][p] && !(m&&d[p]) && !(s&&a[p]) && !y[i][p]) {
                        // fill the spot, and indicate that this row, column and diagonals 
                        // contain this number, c
                        b[r][i]=c; x[r][p]=1; y[i][p]=1;
                        if (m) d[p]=1; if (s)a[p]=1;

                        // move onto to the next number, if you find a solution, stop
                        if (f(c+1,r)) return 1;

                        // with this number in this spot, a solution is impossible, clear
                        // its, and clear the checks
                        b[r][i]=0; x[r][p]=0; y[i][p]=0;
                        if (m) d[p]=0; if (s) a[p]=0;
                }
        }

        return 0; // a solution wasn't found
}

int main() {
        std::cin >> n; // get n from STDIN

        // initialization 
        int i=0,j=0;
        b=new int*[n]; x=new int*[n]; y=new int*[n];
        E(d); E(a);
        R(i)
                E(b[i]); E(x[i]); E(y[i]); // initialization the inner arrays of b, x, y
                d[i]=0; a[i]=0;

                R(j)
                        b[i][j]=0; x[i][j]=0; y[i][j]=0; // ensure each point is initialized as 0
                }
        }

        // find a solution starting at the top-left corner and print it if it finds one
        if (f(1,0)) {
                R(i)
                        R(j)
                                std::cout<<b[i][j];
                        }
                        std::cout<<std::endl;
                }
        }
}

Setelah membaca ulang kode, saya menyadari beberapa pemeriksaan mungkin tidak diperlukan, seperti if (x[r][p]) return f(c+1,r);. Saya sedang berusaha memperpendeknya.
hargasinski

0

Clojure, (215 + 258) * 0.8 = 378.4 (174 + 255) * 0.8 = 343.2

Dibagi menjadi dua bagian: penghitungan kesalahan Sdan fungsi anonim yang melakukan optimasi sebenarnya melalui pencarian Tabu .

Pembaruan: lebih pendek S(menghitung nilai berbeda dalam grup), status awal yang kurang optimal (tanpa acak).

(defn S[I n](count(mapcat set(vals(apply merge-with concat(flatten(for[R[(range n)]i R j R v[[(I(+(* n i)j))]]][{[1 i]v}{[2 j]v}(if(= i j){3 v})(if(=(- n 1 i)j){4 v})])))))))
#(if-let[s({1[0]2()3()}%)]s(loop[I(vec(for[R[(range %)]i R j R]i))P #{}](let[[s I](last(sort-by first(for[R[(range(count I))]i R j R I[(assoc(assoc I i(I j))j(I i))]:when(not(P I))][(S I %)I])))](if(=(*(+(* % 2)2)%)s)(partition % I)(recur I(conj P I))))))

Benchmark inti tunggal (dalam milidetik) untuk 4, 5, 6 dan 7 berjalan 3 kali:

[[  131.855337   132.96267    138.745981]
 [ 1069.187325  1071.189488  1077.339372]
 [ 9114.736987  9206.65368   9322.656693]
 [36546.309408 36836.567267 36928.346312]]

Asli:

(defn S[I n](apply +(flatten(for[p(concat(partition n I)(for[p(apply map vector(partition n(range(count I))))](map I p))[(take-nth(inc n)I)][(rest(butlast(take-nth(dec n)I)))])](remove #{1}(vals(frequencies p)))))))
#(if-let[s({1[0]2()3()}%)]s(loop[I(vec(flatten(map shuffle(repeat %(range %)))))P #{}](let[[s I](first(sort-by first(for[R[(range(count I))]i R j R I[(assoc(assoc I i(I j))j(I i))]:when(not(P I))][(S I %)I])))](if(= s 0)(partition % I)(recur I(conj P I))))))

Saya berharap Slebih pendek, tetapi karena hanya menghitung kejadian lebih dari satu / partisi kriteria berhenti adalah sederhana (= s 0).

Banyak siklus CPU yang terbuang untuk swap yang tidak berguna, misalnya itu tidak meningkatkan skor jika Anda bertukar 2 dengan2 , dan Anda tidak perlu nomor pertukaran antara baris karena mereka semua memiliki nilai yang berbeda untuk memulai.

Tolak ukur dengan Intel 6700K (dalam milidetik):

(defn S[I n]( ... )
(def F #( ... ))

(defmacro mytime[expr]
  `(let [start# (. System (nanoTime)) ret# ~expr]
     (/ (double (- (. System (nanoTime)) start#)) 1000000.0)))

(pprint(vec(for[n[4 5 6 7]](vec(sort(repeatedly 5 #(mytime (F n)))))))

[[  43.445902   45.895107   47.277399   57.681634    62.594037]
 [ 222.964582  225.467034  240.532683  330.237721   593.686911]
 [2285.417473 2531.331068 3002.597908 6361.591714  8331.809410]
 [3569.62372  4779.062486 5725.905756 7444.941763 14120.796615]]

Multithreaded dengan pmap:

[[   8.881905  16.343714   18.87262  18.9717890   22.194430]
 [  90.963870 109.719332  163.00299  245.824443  385.365561]
 [ 355.872233 356.439256 1534.31059 2593.482767 3664.221550]
 [1307.727115 1554.00260 2068.35932 3626.878526 4029.543011]]
Dengan menggunakan situs kami, Anda mengakui telah membaca dan memahami Kebijakan Cookie dan Kebijakan Privasi kami.
Licensed under cc by-sa 3.0 with attribution required.