Điền vào các hàng, cột và đường chéo của lưới NxN từ 1 đến N


26

Bài tập

Cho đầu vào N, tạo và xuất một lưới NxN trong đó mỗi hàng, cột và hai đường chéo chứa các số từ 1 đến N(hoặc 0 đến N−1 nếu dễ dàng hơn).

Đầu vào

Đầu vào là một số nguyên dương N. Nó đại diện cho số lượng cột và hàng trong lưới. Đối với vấn đề này, bạn có thể giả sử Nsẽ có kích thước hợp lý 4 ≤ N ≤ 8hoặc ( 1 ≤ N ≤ 8nếu bạn nhận phần thưởng bên dưới).

Đầu ra

Đầu ra sẽ là lưới N× N. Trong lưới, mỗi hàng chỉ chứa các số từ 1 đến N, mỗi cột chỉ chứa các số từ 1 đến Nvà hai đường chéo có chiều dài N(một từ (0,0)đến (N-1,N-1)và một từ (0,N-1)đến (N-1, 0)) chỉ chứa các số từ 1 đến N. Bạn có thể sử dụng các số từ 0 đến N−1. Đối với mỗi N, có nhiều giải pháp có thể, bạn chỉ cần in cái đầu tiên bạn tìm thấy. Bạn không cần phải in khoảng trắng giữa các số.

Những ràng buộc

Mã của bạn sẽ có thể lặp lại tạo ra kết quả cho N >= 7. Đó là, nếu bạn thực sự có thể chạy và nhận được giải pháp cho N = 7mã của mình mỗi lần, bạn vẫn ổn. Về giới hạn tuyệt đối, mã của bạn sẽ có thể giải quyết N = 7trong vòng dưới 10 phút mỗi lần bạn chạy nó (nghĩa là, nếu bạn phụ thuộc vào số ngẫu nhiên, trong trường hợp xấu nhất, mã của bạn vẫn sẽ hoàn thành trong vòng dưới 10 phút N = 7) .

Ví dụ

  • Đầu vào: 4

    Một đầu ra có thể:

    1 2 3 4
    3 4 1 2
    4 3 2 1
    2 1 4 3
    
  • Đầu vào: 5

    Một đầu ra có thể:

    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
    
  • Đầu vào: 8

    Một đầu ra có thể:

    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
    

Chấm điểm

Đây là , vì vậy mã ngắn nhất tính bằng byte sẽ thắng, với một ngoại lệ. Đối với đầu vào N = 2, 3không có giải pháp hợp lệ. Nếu mã của bạn có thể xử lý việc này (chạy đến hoàn thành mà không xuất ra bất cứ điều gì cho các trường hợp này hoặc xuất ra một chuỗi trống) và vẫn xử lý N = 1(đầu ra 1cho nó), hãy giảm 20% số byte của bạn.


1
Liên quan , nhưng một lưới như vậy sẽ không hoạt động ở đây vì yêu cầu đường chéo.
xnor

Tôi thích thử thách này nhưng tôi không thể tìm ra thuật toán cho các giá trị chẵn N. Mã JavaScript này hoạt động N = 1, 5 or 7mặc dù nếu nó giúp được bất cứ ai:for(o="",y=N;y--;o+="\n")for(x=N;x--;)o+=(((N-y)*2+x)%N)+1
user81655

Rất liên quan, có thể trùng lặp: codegolf.stackexchange.com/q/47846/15599
Level River St

@steveverrill Đó không phải là mã golf.
ngẫu nhiên

1
Có lẽ bạn nên rõ ràng hơn về N = 1trường hợp: câu trả lời nhắm đến phần thưởng sẽ trả về 1, chứ không phải chuỗi trống.
Lynn

Câu trả lời:


3

Python 3, 275 260 byte * 0,8 = 220 208 byte

Phương pháp đệ quy / quay lui. Rlà hàm đệ quy, llà coLumn, wlà roW, Klà mục tiếp theo.

Tôi đã chọn đặt nó trong một mảng 1d và in nó ở cuối để làm cho các chỉ mục đơn giản hơn.

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)

Phiên bản bị đánh cắp:

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 , không cạnh tranh

CẬP NHẬT! Cải thiện hiệu suất lớn! n = 7 bây giờ hoàn thành trong vòng dưới 10 phút! Xem giải thích ở phía dưới!

Đây là niềm vui tốt để viết. Đây là một người giải quyết vũ phu cho vấn đề này được viết bằng Funciton. Một số thực tế:

  • Nó chấp nhận một số nguyên trên STDIN. Bất kỳ khoảng trắng bên ngoài nào sẽ phá vỡ nó, bao gồm một dòng mới sau số nguyên.
  • Nó sử dụng các số từ 0 đến n - 1 (không phải 1 đến n ).
  • Nó lấp đầy lưới Quay ngược lại, vì vậy bạn có được một giải pháp trong đó hàng dưới cùng đọc 3 2 1 0thay vì nơi hàng trên cùng đọc 0 1 2 3.
  • Nó xuất chính xác 0(giải pháp duy nhất) cho n = 1.
  • Đầu ra trống cho n = 2 và n = 3.
  • Khi được biên dịch thành exe, mất khoảng 8¼ phút cho n = 7 (khoảng một giờ trước khi cải thiện hiệu suất). Nếu không biên dịch (sử dụng trình thông dịch) thì sẽ mất khoảng 1,5 lần thời gian, vì vậy sử dụng trình biên dịch là đáng giá.
  • Như một cột mốc cá nhân, đây là lần đầu tiên tôi viết toàn bộ chương trình Funciton mà không viết chương trình đầu tiên bằng ngôn ngữ mã giả. Tôi đã viết nó trong C # thực tế đầu tiên mặc dù.
  • (Tuy nhiên, đây không phải là lần đầu tiên tôi thực hiện thay đổi để cải thiện ồ ạt hiệu năng của một thứ gì đó trong Funciton. Lần đầu tiên tôi làm điều đó là trong chức năng giai thừa. thuật toán nhân hoạt động như thế nào . Chỉ trong trường hợp bạn tò mò.)

Nếu không có thêm rắc rối:

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

Giải thích về phiên bản đầu tiên

Phiên bản đầu tiên mất khoảng một giờ để giải quyết n = 7. Phần sau đây giải thích chủ yếu cách thức phiên bản chậm này hoạt động. Ở phía dưới tôi sẽ giải thích những thay đổi tôi đã thực hiện để có được nó dưới 10 phút.

Chuyến tham quan thành bit

Chương trình này cần bit. Nó cần rất nhiều bit, và nó cần chúng ở tất cả các vị trí thích hợp. Các lập trình viên Funciton có kinh nghiệm đã biết rằng nếu bạn cần n bit, bạn có thể sử dụng công thức

2 ^ n-1

mà trong Funciton có thể được thể hiện là

(1 << n) - 1

Khi thực hiện tối ưu hóa hiệu suất của tôi, tôi nhận ra rằng tôi có thể tính toán cùng một giá trị nhanh hơn nhiều bằng cách sử dụng công thức này:

¬ (<< 1 << n)

Tôi hy vọng bạn sẽ tha thứ cho tôi rằng tôi đã không cập nhật tất cả đồ họa phương trình trong bài viết này cho phù hợp.

Bây giờ, giả sử bạn không muốn một khối bit liền kề; thực tế, bạn muốn n bit theo chu kỳ đều đặn mỗi bit thứ k , như vậy:

                                 LSB
                                  ↓
00000010000001000000100000010000001
                            └──┬──┘
                               k

Công thức cho việc này khá đơn giản một khi bạn biết:

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

Trong mã, hàm Ӝlấy các giá trị nk và tính công thức này.

Theo dõi các số được sử dụng

n ² số trong lưới cuối cùng và mỗi số có thể là bất kỳ giá trị n nào. Để theo dõi những số nào được phép trong mỗi ô, chúng tôi duy trì một số bao gồm n bit, trong đó một bit được đặt để chỉ ra rằng một giá trị cụ thể được lấy. Ban đầu con số này là 0, rõ ràng.

Thuật toán bắt đầu ở góc dưới bên phải. Sau khi đoán được số thứ nhất là số 0, chúng ta cần theo dõi thực tế là số 0 không còn được phép trong bất kỳ ô nào dọc theo cùng một hàng, cột và đường chéo:

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

Để kết thúc này, chúng tôi tính toán bốn giá trị sau:

  • Hàng hiện tại: Chúng ta cần n bit mỗi bit thứ n (một trên mỗi ô), sau đó chuyển nó sang hàng hiện tại r , ghi nhớ mỗi hàng chứa n ² bit:

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

  • Cột hiện tại: Chúng ta cần n bit mỗi bit thứ n (một trên mỗi hàng), sau đó chuyển nó sang cột hiện tại c , ghi nhớ mỗi cột chứa n bit:

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

  • Chuyển tiếp chéo: Chúng tôi cần n bit mỗi ... (bạn có chú ý không? Nhanh chóng, tìm ra nó!) ... n ( n +1) -th bit (hoàn thành tốt!), Nhưng chỉ khi chúng tôi thực sự vào đường chéo phía trước:

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

  • Đường chéo ngược: Hai điều ở đây. Đầu tiên, làm thế nào để chúng ta biết nếu chúng ta đang ở trên đường chéo ngược? Về mặt toán học, điều kiện là c = ( n - 1) - r , giống như c = n + (- r - 1). Này, điều đó có nhắc nhở bạn điều gì không? Đúng vậy, đó là hai phần bù, vì vậy chúng ta có thể sử dụng phủ định bitwise (rất hiệu quả trong Funciton) thay vì giảm dần. Thứ hai, công thức trên giả định rằng chúng ta muốn thiết lập bit quan trọng nhất, nhưng theo đường chéo ngược chúng ta không có, vì vậy chúng ta phải thay đổi nó bằng cách ... bạn có biết không? ... Đúng vậy, n ( n - 1).

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

    Đây cũng là người duy nhất có khả năng chia cho 0 nếu n = 1. Tuy nhiên, Funciton không quan tâm. 0 ÷ 0 chỉ là 0, bạn không biết sao?

Trong mã, hàm Җ( hàm dưới cùng) lấy n và một chỉ mục (từ đó nó tính rc bằng cách chia và phần còn lại), tính bốn giá trị này và orkết hợp chúng với nhau.

Thuật toán brute-force

Thuật toán brute-force được thực hiện bởi Ӂ(hàm ở trên cùng). Phải mất n (kích thước lưới), chỉ mục (trong đó trong lưới chúng ta hiện đang đặt một số) và lấy (số có n bit cho chúng ta biết số nào chúng ta vẫn có thể đặt trong mỗi ô).

Hàm này trả về một chuỗi các chuỗi. Mỗi chuỗi là một giải pháp đầy đủ cho lưới. Đó là một người giải quyết hoàn chỉnh; nó sẽ trả về tất cả các giải pháp nếu bạn cho phép, nhưng nó trả về chúng như một chuỗi đánh giá lười biếng.

  • Nếu chỉ mục đã về 0, chúng tôi đã lấp đầy thành công toàn bộ lưới, vì vậy chúng tôi trả về một chuỗi chứa chuỗi trống (một giải pháp duy nhất không bao gồm bất kỳ ô nào). Chuỗi rỗng là 0và chúng tôi sử dụng hàm thư viện để biến chuỗi đó thành một chuỗi phần tử đơn.

  • Kiểm tra được mô tả dưới cải tiến hiệu suất dưới đây xảy ra ở đây.

  • Nếu chỉ số chưa đạt đến 0, chúng ta sẽ giảm nó đi 1 để lấy chỉ số mà tại đó chúng ta cần đặt một số (gọi đó là ix ).

    Chúng tôi sử dụng để tạo ra một chuỗi lười biếng chứa các giá trị từ 0 đến n - 1.

    Sau đó, chúng tôi sử dụng ɓ(liên kết đơn âm) với lambda thực hiện theo thứ tự sau:

    • Trước tiên hãy xem bit có liên quan được thực hiện để quyết định xem số đó có hợp lệ ở đây hay không. Chúng ta có thể đặt một số i khi và chỉ khi đã lấy & (1 << ( n × ix ) << i ) chưa được đặt. Nếu nó được đặt, trả về 0(chuỗi trống).
    • Sử dụng Җđể tính toán các bit tương ứng với hàng, cột và đường chéo hiện tại. Thay đổi nó bởi tôi và sau đó orđược thực hiện .
    • Gọi đệ quy Ӂđể lấy tất cả các giải pháp cho các ô còn lại, chuyển nó qua ix mới được thực hiệnix giảm dần . Điều này trả về một chuỗi các chuỗi không đầy đủ; mỗi chuỗi có các ký tự ix (lưới được điền vào chỉ mục ix ).
    • Sử dụng ɱ(bản đồ) để đi qua các giải pháp được tìm thấy và sử dụng để nối i đến cuối mỗi giải pháp. Nối một dòng mới nếu chỉ số là bội số của n , nếu không thì là khoảng trắng.

Tạo kết quả

Chương trình chính gọi Ӂ(forcer brute) với n , index = n ² (hãy nhớ rằng chúng ta điền vào lưới ngược) và lấy = 0 (ban đầu không có gì được thực hiện). Nếu kết quả của việc này là một chuỗi trống (không tìm thấy giải pháp), hãy xuất chuỗi trống. Mặt khác, xuất chuỗi đầu tiên trong chuỗi. Lưu ý rằng điều này có nghĩa là nó sẽ chỉ đánh giá phần tử đầu tiên của chuỗi, đó là lý do tại sao người giải không tiếp tục cho đến khi tìm thấy tất cả các giải pháp.

Cải thiện hiệu suất

(Đối với những người đã đọc phiên bản cũ của giải thích: chương trình không còn tạo ra một chuỗi các chuỗi cần được tách riêng thành một chuỗi cho đầu ra; nó chỉ tạo ra một chuỗi các chuỗi trực tiếp. Nhưng đó không phải là cải tiến chính. Nó đến rồi.)

Trên máy của tôi, exe đã biên dịch của phiên bản đầu tiên mất khá nhiều thời gian chính xác là 1 giờ để giải quyết n = 7. Điều này không nằm trong giới hạn thời gian nhất định là 10 phút, vì vậy tôi đã không nghỉ ngơi. (Chà, thực ra, lý do tôi không nghỉ ngơi là vì tôi có ý tưởng này về cách tăng tốc nó một cách ồ ạt.)

Thuật toán như được mô tả ở trên dừng tìm kiếm và quay lui của nó mỗi khi nó gặp một ô trong đó tất cả các bit trong số đã lấy được đặt, chỉ ra rằng không có gì có thể được đưa vào ô này.

Tuy nhiên, thuật toán sẽ tiếp tục lấp đầy lưới một cách vô ích đến ô mà tất cả các bit đó được đặt. Sẽ nhanh hơn nhiều nếu nó có thể dừng ngay khi bất kỳ ô nào được điền đầy đủ đã có tất cả các bit được đặt, điều này cho thấy rằng chúng ta không bao giờ có thể giải quyết phần còn lại của lưới cho dù chúng ta đặt số nào vào nó Nhưng làm thế nào để bạn kiểm tra một cách hiệu quả liệu có bất kỳ ô nàon bit được đặt mà không đi qua tất cả chúng không?

Thủ thuật bắt đầu bằng cách thêm một bit trên mỗi ô vào số đã lấy . Thay vì những gì đã được hiển thị ở trên, bây giờ nó trông như thế này:

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

Thay vì n , bây giờ có n ² ( n + 1) bit trong số này. Hàm điền vào hàng / cột / đường chéo hiện tại đã được thay đổi tương ứng (thực tế, được viết lại hoàn toàn thành trung thực). Mặc dù vậy, hàm đó sẽ vẫn chỉ chứa n bit trên mỗi ô, do đó, bit bổ sung mà chúng ta vừa thêm sẽ luôn như vậy 0.

Bây giờ, giả sử chúng ta đang thực hiện được một nửa tính toán, chúng ta chỉ cần đặt một 1ô ở giữa và số được lấy trông giống như thế này:

                 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

Như bạn có thể thấy, ô trên cùng bên trái (chỉ số 0) và ô giữa bên trái (chỉ mục 10) hiện không thể. Làm thế nào để chúng ta xác định hiệu quả nhất điều này?

Xem xét một số trong đó bit thứ 0 của mỗi ô được đặt, nhưng chỉ tối đa cho chỉ mục hiện tại. Một số như vậy rất dễ tính bằng công thức quen thuộc:

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

Chúng ta sẽ nhận được gì nếu cộng hai số này lại với nhau?

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

Kết quả là:

             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

Như bạn có thể thấy, phần bổ sung tràn vào bit bổ sung mà chúng ta đã thêm, nhưng chỉ khi tất cả các bit cho ô đó được đặt! Do đó, tất cả những gì còn lại phải làm là che dấu các bit đó (cùng công thức như trên, nhưng << n ) và kiểm tra xem kết quả có phải là 0 không:

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

Nếu nó không bằng 0, lưới là không thể và chúng ta có thể dừng lại.


3
HẠNH PHÚC. Anh bạn, thật ấn tượng.
Deusovi

1
Tôi thứ hai bình luận của @ Deusovi, cảm ơn bạn đã nỗ lực rất nhiều vào việc này
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]]

Tôi nhận thấy vấn đề này rất giống với sudoku. Tôi nhớ một người giải sudoku cũ mà tôi đã viết bằng Haskell dựa trên cái khác trong Python. Đây là bài viết mã golf đầu tiên của tôi hoặc cố gắng.

Đây thực hiện tốt các tiền thưởng vì nó sẽ trả về Nothingcho n=2,3Just <result>cho n>=4, nơi <result>là một mảng 2D của các giá trị không thể thiếu.

Xem ở đây để thông dịch viên trực tuyến. Mã đó thực sự dài hơn mã trong bài bởi vì trình thông dịch trực tuyến có các yêu cầu khắt khe hơn về những gì tạo thành một chương trình hoàn chỉnh (quy tắc nói rằng một bài nộp có thể là một chức năng). Trình này nhận đầu vào như là một đối số chức năng.


1
Một vài mẹo nhanh: a) bạn xác định c=[1..r], vì vậy bạn có thể sử dụng nó trong ow. b) minimumBy(\(a,_)(b,_)->compare a b)[...]head$sortOn fst[...]. c) vin v=g0!schỉ được sử dụng một lần, vì vậy đừng định nghĩa nó cả : l=length$g0!s. d) bạn vẫn có một số tên tham số hai chữ cái. e) thay thế Truebằng1<2Falsebằng 2<1. f) and[case g0!s of{[_]->True;_->False}|s<-u]all((==1).length.(g0!))u.
nimi

Mẹo nhanh, phần II: g) (&)m k= có thể được xác định infix : m&k=. h) not(delem (g0!p))notElem d$g0!p. i) concat(...)id=<<(...). j) sử dụng toán tử infix cho h, vd as%bs=.
nimi

3
Mẹo meta nhanh: bạn có thể phân định mã có backticks chính xác bằng cách sử dụng backticks kép ​``like`this``​!
Lynn

4

Bình thường, 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

Lực lượng vũ phu ftw!

Vì điều này về cơ bản tiếp tục thử xáo trộn ngẫu nhiên cho đến khi nó hoạt động (tốt, nó tiếp tục cố gắng n * [shuffle(range(n))]), phải mất một thời gian thực sự rất dài. Dưới đây là một số lần chạy thử để cho bạn biết thời gian cần bao lâu:

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

Đó chỉ là 4 x 4 và nó chạy trong chưa đầy nửa giây. Tôi thực sự gian lận vì đây là thử thách tốt nhất trong số ít thử nghiệm mà hầu hết trong số họ chiếm được một hoặc hai giây.

Tôi vẫn chưa có thời gian trên 5x5 (nó đã chạy đến khi hoàn thành một lần, nhưng đó là trong REPL và tôi đã không định thời gian cho nó).

Lưu ý rằng quy tắc giới hạn thời gian chỉ được chỉnh sửa thành câu hỏi sau khi câu trả lời này được đăng.


Tôi cho rằng điều này không thể làm 7x7 trong vòng mười phút? ^^
Lynn

@Mauris Vâng, đôi khi nó có thể ...;) Đó có phải là một yêu cầu tôi đã bỏ lỡ? Tôi không thấy bất cứ điều gì đề cập đến một giới hạn thời gian trong câu hỏi.
Doorknob

Tôi thấy nó trong các bình luận, (không phải bình luận mới , 12 giờ trước)
edc65

Xin lỗi về điều đó, tôi đã không nghĩ về nó cho đến khi ai đó đề cập đến nó, tôi sẽ chỉnh sửa thử thách ngay bây giờ
hargasinski

1
+1 cho nghệ thuật trừu tượng ASCII trong phiên bản nhận xét của bạn. :)
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).

Chỉnh sửa: đã lưu 16 byte nhờ @Mat

Sử dụng

Gọi a(5).thông dịch viên của bạn cho N=5. Điều này trả về falsecho N=2hoặc N=3.

Vì nó sử dụng thư viện CLPFD nên đây không phải là bruteforce thuần túy. Chương trình này có thể tìm ra giải pháp N=20trong khoảng 15 giây trên máy tính của tôi.

Ungolfed + giải thích:

Điều này về cơ bản hoạt động giống như một bộ giải Sudoku, ngoại trừ các ràng buộc khối được thay thế bằng các ràng buộc đường chéo.

:-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

Rất đẹp! Bạn có thể lưu một byte bằng:maplist(maplist(all_distinct), [R,C,D,E])
mat

1
@mat Cảm ơn lời đề nghị, tiết kiệm 16 byte. Tôi cần phải sử dụng [R,C,[D,E]]mặc dù, bởi vì EDlà danh sách đơn giản.
Gây tử vong

Phải, cách giải quyết rất tốt đẹp!
chiếu

2
@Firthize Chỉ để cho bạn biết, giải pháp của bạn là ấn tượng nhất vì nó là giải pháp duy nhất được giải quyếtN=20
hargasinski

1
@Zequ Cảm ơn! Nhưng đó chủ yếu là do các thư viện tuyệt vời CLPFD của Prolog, mà làm việc nặng nhọc trong các vấn đề như thế này :)
Fatalize

2

CJam, 87 byte - Phần thưởng 20% ​​= 69,6 byte

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

Hardcodes các câu trả lời. Chứa một số không thể in. Hoạt động cho N = 1thông qua N = 8.

Về cơ bản, mỗi dòng trong chuỗi bí ẩn đó chứa các chỉ mục vào danh sách hoán vị của range(N), được mã hóa dưới dạng các ký tự Unicode.

=:i0+\,m!f=lập chỉ mục vào danh sách hoán vị, thêm 0 vào cuối danh sách các chỉ số trước, biểu thị hàng dưới cùng 0 1 2 ... N-1. Dành choN < 4 , mảng 2D kết quả là vô nghĩa.

`1LL]tạo ra một danh sách [N, pretty output, 1, "", ""]. Sau đó, (4e<=bật phần tử đầu tiên ra khỏi danh sách này Nvà lấy min(N, 4) % 4phần tử thứ từ phần còn lại của nó. Dành choN >= 4 , đó là đầu ra, và nếu không thì đó là đầu ra trường hợp đặc biệt cho ba trường hợp đầu tiên.

Hãy thử nó ở đây .


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;}}}

Dùng thử trực tuyến tại đây

Vì một vài câu trả lời đã được đăng, tôi nghĩ rằng tôi sẽ đăng phiên bản golf của mã mà tôi đã sử dụng để tạo đầu ra cho các ví dụ. Đây là lần đầu tiên tôi trả lời , vì vậy mọi phản hồi đều được hoan nghênh. :)

Ungolfed + giải thích:

Về cơ bản, mã này là vũ phu - buộc một giải pháp. Nó bắt đầu ở hàng đầu tiên, với 0. Nó bắt đầu ở vị trí đầu tiên, nếu điểm đó vượt qua tất cả các kiểm tra, nó sẽ chuyển sang số tiếp theo. Nếu nó lấp đầy hàng, nó sẽ chuyển sang hàng tiếp theo. Nếu nó được thực hiện tất cả các hàng, điều đó có nghĩa là một giải pháp đã được tìm thấy. Nếu vị trí không vượt qua tất cả các kiểm tra, nó sẽ chuyển sang vị trí tiếp theo. Nếu nó thực hiện xong hàng, thì nó quay lại, vì một số ở một trong các hàng trước đó ngăn không cho giải pháp.

#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;
                }
        }
}

Sau khi đọc lại mã, tôi nhận ra một số kiểm tra có thể không cần thiết, chẳng hạn như if (x[r][p]) return f(c+1,r);. Tôi đang làm việc để rút ngắn nó.
hargasinski

0

Clojure, (215 + 258) * 0,8 = 378,4 (174 + 255) * 0,8 = 343,2

Chia thành hai phần: đếm lỗi Svà chức năng ẩn danh thực hiện tối ưu hóa thực tế thông qua tìm kiếm Tabu .

Cập nhật: ngắn hơn S(tính các giá trị riêng biệt trong các nhóm), trạng thái bắt đầu ít tối ưu hơn (không xáo trộn).

(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))))))

Điểm chuẩn lõi đơn (tính bằng mili giây) trong 4, 5, 6 và 7 chạy 3 lần:

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

Nguyên:

(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))))))

Tôi muốn Sngắn hơn, nhưng vì nó chỉ tính số lần xuất hiện của nhiều hơn một / phân vùng nên tiêu chí dừng là đơn giản (= s 0).

Nhiều chu kỳ CPU bị lãng phí cho các giao dịch hoán đổi không hữu ích, ví dụ: nó không cải thiện điểm số nếu bạn trao đổi 2 với2 , và bạn không cần phải đến các số trao đổi giữa các hàng như tất cả họ đều có giá trị khác biệt để bắt đầu với.

Điểm chuẩn với Intel 6700K (tính bằng mili giây):

(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]]

Đa luồng với 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]]
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.