Tạo hình vuông Graeco-Latin


24

từ chối trách nhiệm: Tôi không biết về bất kỳ giải pháp không bruteforce nào

Một hình vuông Graeco-Latin là, cho hai bộ có cùng độ dài n , cách sắp xếp các ô n×n , mỗi ô chứa một cặp duy nhất (trên toàn bộ hình vuông) của một phần tử của tập thứ nhất và một phần tử của tập thứ hai, chẳng hạn rằng tất cả các yếu tố đầu tiên và tất cả các yếu tố thứ hai của các cặp là duy nhất trong hàng và cột của chúng. Các bộ phổ biến nhất được sử dụng là, như người ta có thể đoán, n chữ cái đầu tiên của bảng chữ cái Hy Lạp và Latin.

Dưới đây là hình ảnh của một hình vuông Graeco-Latin:nhập mô tả hình ảnh ở đây

Hình vuông Graeco-Latin hữu ích như âm thanh của chúng ( bài viết trên Wikipedia đề cập đến "thiết kế thí nghiệm, lên lịch thi đấu và xây dựng các ô vuông ma thuật"). Nhiệm vụ của bạn là, đưa ra một số nguyên dương n , để tạo ra một n×n vuông Graeco-Latinh.

Đầu vào

Một số nguyên dương n>2 ; nó được đảm bảo rằng một n×n Graeco-Latin vuông tồn tại (có nghĩa là, n6 ).

Đầu ra

Một hình vuông Graeco-Latin có độ dài cạnh n là một mảng hai chiều, một mảng các mảng, một mảng được làm phẳng hoặc xuất trực tiếp.

Ghi chú

  • Bạn không phải sử dụng bảng chữ cái Hy Lạp và Latinh cụ thể; ví dụ, xuất ra các cặp số nguyên dương cũng được cho phép.
  • Nếu bạn chọn sử dụng một bảng chữ cái không thể được mở rộng tùy ý, bạn phải (về mặt lý thuyết; mã của bạn không phải hoàn thành trước cái chết nhiệt của vũ trụ) hỗ trợ chiều dài tối đa ít nhất là 20.

Đây là , vì vậy đoạn mã ngắn nhất sẽ thắng!



Chúng ta có phải xuất ra một hình vuông không, hoặc có thể xuất tất cả các hình vuông có thể thành một danh sách không?
Nick Kennedy

Câu trả lời:


2

Thạch ,  21  20 byte

-1 nhờ Nick Kennedy (tùy chọn đầu ra phẳng cho phép lưu byte ż"þ`ẎẎQƑ$Ƈ F€p`Z€QƑƇ )

Œ!ṗ⁸Z€Q€ƑƇF€p`Z€QƑƇḢ

Hãy thử trực tuyến! (Quá chậm4trong 60 giây trên TIO, nhưng nếu chúng ta thay thế sức mạnh của Cartesian, bằng Kết hợpœc, nó sẽ hoàn thành - mặc dù 5 chắc chắn sẽ không!)

Làm sao?

Œ!ṗ⁸Z€Q€ƑƇF€p`Z€QƑƇḢ - Link: integer, n
Œ!                   - all permutations of [1..n]
   ⁸                 - chain's left argument, n
  ṗ                  - Cartesian power (that is, all ways to pick n of those permutations, with replacement, not ignoring order)
    Z€               - transpose each
         Ƈ           - filter, keeping those for which:
        Ƒ            -   invariant under:
      Q€             -     de-duplicate each
          F€         - flatten each  
             `       - use this as both arguments of:
            p        -   Cartesian product
              Z€     - transpose each
                  Ƈ  - filter, keeping those for which:
                 Ƒ   -   invariant under:   
                Q    -     de-duplicate (i.e. contains all the possible pairs)
                   Ḣ - head (just one of the Latin-Greaco squares we've found)

Đây là 20 . Ban đầu tôi viết bài này một cách độc lập với bạn, nhưng cuối cùng lại có một thứ khá giống nhau, và sau đó lấy một chút cảm hứng từ việc bạn sử dụng sức mạnh của Cartesian thay cho một con đê hoán vị, vì vậy có lẽ tốt nhất là sử dụng nó để cải thiện bạn. Lưu ý rằng bạn đã viết sai Graeco trong lời giải thích của bạn.
Nick Kennedy

Cảm ơn Nick, tôi không nhận thấy chúng tôi được phép xuất bản phiên bản phẳng.
Jonathan Allan


3

R , 164 148 byte

-Nhiều byte nhờ Giuseppe.

n=scan()
`!`=function(x)sd(colSums(2^x))
m=function()matrix(sample(n,n^2,1),n)
while(T)T=!(l=m())|!(g=m())|!t(l)|!t(g)|1-all(1:n^2%in%(n*l+g-n))
l
g

Hãy thử trực tuyến!

Không hiệu quả về mặt kịch tính - Tôi nghĩ nó thậm chí còn tồi tệ hơn các phương pháp vũ phu khác. Ngay cả đối với n=3, nó có thể sẽ hết thời gian trên TIO. Đây là một phiên bản thay thế (155 byte) hoạt động n=3trong khoảng 1 giây.

m1nnlg

  1. all(1:n^2%in%(n*l+g-n))n2l × g
  2. lghình vuông Latin?

!nlg2^l2n+12lt(l)lgsdn=0n=1 , điều này ổn theo OP.

Một lưu ý cuối cùng: như thường thấy trong golf mã R, tôi đã sử dụng biến T, được khởi tạo là TRUE, để thu được một vài byte. Nhưng điều này có nghĩa là khi tôi cần giá trị thực TRUEtrong định nghĩa của m(tham số replacetrong sample), tôi phải sử dụng 1thay vì T. Tương tự, vì tôi định nghĩa lại !là một hàm khác với phủ định, tôi phải sử dụng 1-all(...)thay vì !all(...).


2

JavaScript (ES6),  159 147  140 byte

n×n cặp số nguyên không âm .

Đây là một tìm kiếm vũ phu đơn giản, và do đó rất chậm.

n=>(g=(m,j=0,X=n*n)=>j<n*n?!X--||m.some(([x,y],i)=>(X==x)+(Y==y)>(j/n^i/n&&j%n!=i%n),g(m,j,X),Y=X/n|0,X%=n)?o:g([...m,[X,Y]],j+1):o=m)(o=[])

Hãy thử trực tuyến!(với đầu ra được chỉnh sửa)

Đã bình luận

n => (                      // n = input
  g = (                     // g is the recursive search function taking:
    m,                      //   m[] = flattened matrix
    j = 0,                  //   j   = current position in m[]
    X = n * n               //   X   = counter used to compute the current pair
  ) =>                      //
    j < n * n ?             // if j is less than n²:
      !X-- ||               //   abort right away if X is equal to 0; decrement X
      m.some(([x, y], i) => //   for each pair [x, y] at position i in m[]:
        (X == x) +          //     yield 1 if X is equal to x OR Y is equal to y
        (Y == y)            //     yield 2 if both values are equal
                            //     or yield 0 otherwise
        >                   //     test whether the above result is greater than:
        ( j / n ^ i / n &&  //       - 1 if i and j are neither on the same row
          j % n != i % n    //         nor the same column
        ),                  //       - 0 otherwise
                            //     initialization of some():
        g(m, j, X),         //       do a recursive call with all parameters unchanged
        Y = X / n | 0,      //       start with Y = floor(X / n)
        X %= n              //       and X = X % n
      ) ?                   //   end of some(); if it's falsy (or X was equal to 0):
        o                   //     just return o[]
      :                     //   else:
        g(                  //     do a recursive call:
          [...m, [X, Y]],   //       append [X, Y] to m[]
          j + 1             //       increment j
        )                   //     end of recursive call
    :                       // else:
      o = m                 //   success: update o[] to m[]
)(o = [])                   // initial call to g with m = o = []

144 ? (Trên điện thoại của tôi, vì vậy không hoàn toàn chắc chắn rằng nó hoạt động)
Shaggy

Tôi cũng không nghĩ bạn cần o; bạn chỉ có thể quay lại mvào cuối cho 141
Shaggy

@Shaggy Cả hai phiên bản sẽ thất bại cho n= =5(có lẽ vì đó là kích thước đầu tiên mà chúng tôi thực sự cần quay lại - nhưng tôi không thực sự kiểm tra).
Arnauld

2

Haskell , 207 143 233 byte

(p,q)!(a,b)=p/=a&&q/=b
e=filter
f n|l<-[1..n]=head$0#[(c,k)|c<-l,k<-l]$[]where
	((i,j)%p)m|j==n=[[]]|1>0=[q:r|q<-p,all(q!)[m!!a!!j|a<-[0..i-1]],r<-(i,j+1)%e(q!)p$m]
	(i#p)m|i==n=[[]]|1>0=[r:o|r<-(i,0)%p$m,o<-(i+1)#e(`notElem`r)p$r:m]

Hãy thử trực tuyến!

OK, tôi nghĩ rằng cuối cùng tôi đã nhận được nó. Nó hoạt động tốt với n = 5, n = 6 lần trên TIO nhưng tôi nghĩ đó có thể là do thuật toán mới này không hiệu quả và về cơ bản kiểm tra tất cả các khả năng cho đến khi tìm thấy một khả năng hoạt động. Bây giờ tôi đang chạy n = 6 trên máy tính xách tay của mình để xem liệu nó có kết thúc sau một thời gian nữa không.

Một lần nữa xin cảm ơn @someone vì đã chỉ ra các lỗi trong các phiên bản trước của tôi


1
Tôi không biết Haskell, nhưng điều này dường như có lỗi với tôi khi tôi thay đổi "4" ở chân trang thành 5. Tôi có đang gọi điều này một cách chính xác không?
đại từ của tôi là monicareinstate

@someone Bắt tốt, tôi nên kiểm tra điều đó. Tôi thực sự không chắc chắn điều gì đang xảy ra ở đây, điều này có thể mất một lúc để gỡ lỗi
user1472751

1
Tôi nghĩ rằng điều này vẫn còn một lỗi; khi chạy với n = 5, tuple (1,1) xuất hiện hai lần.
đại từ của tôi là monicareinstate

@someone Man, vấn đề này khó hơn tôi nghĩ rất nhiều. Tôi chỉ không thể tìm thấy một cách đáng tin cậy để khóa tất cả các ràng buộc cùng một lúc. Ngay khi tôi tập trung vào nhau, một người khác trượt khỏi tầm tay tôi. Bây giờ tôi sẽ đánh dấu là không cạnh tranh cho đến khi tôi có thể tìm thêm thời gian để làm việc này. Xin lỗi vì đã không kiểm tra kỹ lưỡng như tôi nên có
user1472751

1

C #, 520 506 494 484 byte

class P{static void Main(string[]a){int n=int.Parse(a[0]);int[,,]m=new int[n,n,2];int i=n,j,k,p,I,J;R:for(;i-->0;)for(j=n;j-->0;)for(k=2;k-->0;)if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)goto Q;Q:for(i=n;i-->0;)for(j=n;j-->0;){for(k=2;k-->0;)for(p=n;p-->0;)if(p!=i&&m[i,j,k]==m[p,j,k]||p!=j&&m[i,j,k]==m[i,p,k])goto R;for(I=i;I<n;I++)for(J=0;J<n;J++)if(I!=i&&J!=j&&m[i,j,0]==m[I,J,0]&&m[i,j,1]==m[I,J,1])goto R;}for(i=n;i-->0;)for(j=n;j-->0;)System.Console.Write(m[i,j,0]+"-"+m[i,j,1]+" ");}}

Thuật toán findinf một hình vuông rất đơn giản. Đó là ... tàn bạo. Vâng, thật ngu ngốc, nhưng mã golf không phải là về tốc độ của một chương trình, phải không?

Mã trước khi làm cho nó ngắn hơn:

using System;

public class Program
{
    static int[,,] Next(int[,,] m, int n){
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                for (int k = 0; k < 2; k++)
                {
                    if ((m[i, j, k] = (m[i, j, k] + 1) % n) != 0)
                    {
                        return m;
                    }
                }
            }
        }
        return m;
    }
    static bool Check(int[,,] m, int n)
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                for (int k = 0; k < 2; k++)
                {
                    for (int p = 0; p < n; p++)
                    {
                        if (p != i)
                            if (m[i, j, k] == m[p, j, k])
                                return false;
                    }
                    for (int p = 0; p < n; p++)
                    {
                        if (p != j)
                            if (m[i, j, k] == m[i, p, k])
                                return false;
                    }
                }
            }
        }

        for (int i_1 = 0; i_1 < n; i_1++)
        {
            for (int j_1 = 0; j_1 < n; j_1++)
            {
                int i_2 = i_1;
                for (int j_2 = j_1 + 1; j_2 < n; j_2++)
                {
                    if (m[i_1, j_1, 0] == m[i_2, j_2, 0] && m[i_1, j_1, 1] == m[i_2, j_2, 1])
                        return false;
                }
                for (i_2 = i_1 + 1; i_2 < n; i_2++)
                {
                    for (int j_2 = 0; j_2 < n; j_2++)
                    {
                        if (m[i_1, j_1, 0] == m[i_2, j_2, 0] && m[i_1, j_1, 1] == m[i_2, j_2, 1])
                            return false;
                    }
                }
            }
        }
        return true;
    }
    public static void Main()
    {
        int n = 3;
        Console.WriteLine(n);
        int maxi = (int)System.Math.Pow((double)n, (double)n*n*2);
        int[,,] m = new int[n, n, 2];
        Debug(m, n);
        do
        {
            m = Next(m, n);
            if (m == null)
            {
                Console.WriteLine("!");
                return;
            }
            Console.WriteLine(maxi--);
        } while (!Check(m, n));


        Debug(m, n);
    }

    static void Debug(int[,,] m, int n)
    {
        for (int i = 0; i < n; i++)
        {
            for (int j = 0; j < n; j++)
            {
                Console.Write(m[i, j, 0] + "-" + m[i, j, 1] + " ");
            }
            Console.WriteLine();
        }
        Console.WriteLine();
    }
}

Bây giờ, nếu bạn muốn kiểm tra nó với n = 3, bạn sẽ phải chờ như một giờ, vì vậy đây là một phiên bản khác:

public static void Main()
{
    int n = 3;
    Console.WriteLine(n);
    int maxi = (int)System.Math.Pow((double)n, (double)n*n*2);        
    int[,,] result = new int[n, n, 2];
    Parallel.For(0, n, (I) =>
    {
        int[,,] m = new int[n, n, 2];
        for (int i = 0; i < n; i++)
            for (int j = 0; j < n; j++)
            {
                m[i, j, 0] = I;
                m[i, j, 1] = I;
            }
        while (true)
        {
            m = Next(m, n);
            if (Equals(m, n, I + 1))
            {
                break;
            }
            if (Check(m, n))
            {
                Debug(m, n);
            }
        }
    });
}

Cập nhật: quên xóa "công khai".

Cập nhật: đã sử dụng "Hệ thống." thay vì "sử dụng hệ thống;"; Ngoài ra, nhờ Kevin Cruijssen , đã sử dụng "a" thay vì "args".

Cập nhật: cảm ơn gastropnerai đó .


argscó thể a:)
Kevin Cruijssen

Mỗi vòng lặp for có thể được chuyển đổi từ for(X = 0; X < Y; X++)sang for(X = Y; X-->0; ), nên lưu một byte trên mỗi vòng lặp.
dạ dày

1
Bạn đã thử Trình biên dịch tương tác Visual C # chưa? Nó có thể lưu byte. Bạn cũng có thể gửi một chức năng ẩn danh. Bạn cũng có thể gán i = 0trong định nghĩa ivà lưu một byte.
đại từ của tôi là monicareinstate

405 byte dựa trên đề xuất của ai đó. Tất nhiên, nó hết thời gian sau 60 giây trên TIO, nhưng nó tiết kiệm byte bằng cách sử dụng lambda và Trình biên dịch tương tác với ẩn System. Ngoài ra, if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)có thể được if((m[i,j,k]=-~m[i,j,k]%n)>0).
Kevin Cruijssen

@Kevin Tôi không thực sự cảm thấy muốn đọc qua đoạn mã đó khi cố gắng đánh gôn. Bạn có chắc phần in ấn hoạt động đúng không? Có vẻ như nó nên sử dụng Writehoặc có thể lưu byte bằng cách thêm \nvào chuỗi bên trong cuộc gọi hoặc bị hỏng. Tôi nghĩ rằng bạn cũng có thể trả lại một mảng trực tiếp.
đại từ của tôi là monicareinstate

1

Octave , 182 byte

Phương pháp Brute force, TIO tiếp tục hết thời gian và tôi đã phải chạy nó rất nhiều lần để có được đầu ra cho n = 3, nhưng về mặt lý thuyết thì điều này sẽ ổn. Thay vì các cặp như (1,2), nó tạo ra một ma trận gồm các liên hợp phức tạp như 1 + 2i. Điều này có thể kéo dài quy tắc một chút, nhưng theo tôi nó sẽ phù hợp với yêu cầu đầu ra. Mặc dù phải có một cách tốt hơn để thực hiện hai dòng theo tuyên bố funcino, nhưng tôi không chắc chắn vào lúc này.

function[c]=f(n)
c=[0,0]
while(numel(c)>length(unique(c))||range([imag(sum(c)),imag(sum(c.')),real(sum(c)),real(sum(c.'))])>0)
a=fix(rand(n,n)*n);b=fix(rand(n,n)*n);c=a+1i*b;
end
end

Hãy thử trực tuyến!


0

Ngôn ngữ Wolfram (Mathicala) , 123 byte

P=Permutations
T=Transpose
g:=#&@@Select[T[Intersection[x=P[P@Range@#,{#}],T/@x]~Tuples~2,2<->4],DuplicateFreeQ[Join@@#]&]&

Hãy thử trực tuyến!

tôi sử dụng TwoWayRule ký hiệu Transpose[...,2<->4]để hoán đổi kích thước thứ 2 và thứ 4 của một mảng; nếu không thì điều này khá đơn giản.

Ung dung:

(* get all n-tuples of permutations *)
semiLSqs[n_] := Permutations@Range@n // Permutations[#, {n}] &;

(* Keep only the Latin squares *)
LSqs[n_] := semiLSqs[n] // Intersection[#, Transpose /@ #] &;

isGLSq[a_] := Join @@ a // DeleteDuplicates@# == # &;

(* Generate Graeco-Latin Squares from all pairs of Latin squares *)
GLSqs[n_] := 
  Tuples[LSqs[n], 2] // Transpose[#, 2 <-> 4] & // Select[isGLSq];

0

Con trăn 3 , 271 267 241 byte

Phương pháp tiếp cận lực lượng: Tạo ra tất cả các hoán vị của các cặp cho đến khi tìm thấy hình vuông Graeco-Latin. Quá chậm để tạo ra bất cứ thứ gì lớn hơnn=3 trên TIO.

Cảm ơn alexz02 vì đã chơi golf 26 byte và đến trần để chơi golf 4 byte.

Hãy thử trực tuyến!

from itertools import*
def f(n):
 s=range(n);l=len
 for r in permutations(product(s,s)):
  if all([l({x[0]for x in r[i*n:-~i*n]})*l({x[1]for x in r[i*n:-~i*n]})*l({r[j*n+i][0]for j in s})*l({r[j*n+i][1]for j in s})==n**4for i in s]):return r

Giải trình:

from itertools import *  # We will be using itertools.permutations and itertools.product
def f(n):  # Function taking the side length as a parameter
 s = range(n)  # Generate all the numbers from 0 to n-1
 l = len  # Shortcut to compute size of sets
 for r in permutations(product(s, s)):  # Generate all permutations of all pairs (Cartesian product) of those numbers, for each permutation:
  if all([l({x[0] for x in r[i * n : (- ~ i) * n]})  # If the first number is unique in row i ...
        * l({x[1] for x in r[i * n:(- ~ i) * n]})  # ... and the second number is unique in row i ...
        * l({r[j * n + i][0] for j in s})  # ... and the first number is unique in column i ...
        * l({r[j * n + i][1] for j in s})  # ... and the second number is unique in column i ...
        == n ** 4 for i in s]):  # ... in all columns i:
   return r  # Return the square

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.