Graeco- 라틴 사각형 생성


24

면책 조항 : 나는 Bruteforce가 아닌 솔루션을 모른다

Graeco-Latin 제곱은 동일한 길이 의 두 세트에 대해 셀로 구성된 배열이며, 각각은 첫 번째 세트의 요소와 두 번째 세트의 요소의 고유 한 (전체 사각형에 걸쳐) 쌍을 포함합니다. 쌍의 모든 첫 번째 요소와 두 번째 요소는 모두 행과 열에서 고유합니다. 가장 일반적으로 사용되는 세트 는 그리스어 및 라틴 알파벳 의 첫 자입니다.nn×nn

다음은 4x4 Graeco- 라틴 스퀘어 사진입니다.여기에 이미지 설명을 입력하십시오

Graeco-Latin 사각형은 소리만큼 유용합니다 ( Wikipedia 기사 에서는 "실험 디자인, 토너먼트 예약 및 마법 사각형 구성"에 대해 언급합니다). Graeco-Latin square 를 생성 하는 양의 정수 주어진 작업입니다 .nn×n

입력

양의 정수 ; Graeco-Latin 정사각형이 존재 함을 보장 합니다 (즉, ).n>2n×nn6

산출

측면 길이 n이 2 차원 배열, 배열 배열, 편평 배열 또는 직접 출력되는 Graeco-Latin 정사각형.

노트

  • 그리스어 및 라틴어 알파벳을 구체적으로 사용할 필요는 없습니다. 예를 들어, 양의 정수 쌍 출력도 허용됩니다.
  • 임의로 확장 할 수없는 알파벳을 사용하기로 선택한 경우 (이론적으로, 우주의 열사병이되기 전에 코드를 완료하지 않아도 됨) 최대 변의 길이는 20 이상이어야합니다.

이것은 이므로 가장 짧은 코드가 승리합니다!



하나의 정사각형을 출력해야합니까, 아니면 가능한 모든 정사각형을 목록으로 출력해도 괜찮습니까?
Nick Kennedy

답변:


2

젤리 ,  21  20 바이트

Nick Kennedy 덕분에 -1 (플랫 출력 옵션은 의 바이트 저장을 허용합니다 )ż"þ`ẎẎQƑ$Ƈ F€p`Z€QƑƇ

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

온라인으로 사용해보십시오! (너무 느린 위해4우리는 데카르트 전원을 교체하는 경우 TIO에 60 년대, 그러나, 조합과 함께,œc, 그것은 완료 - 비록 5가 분명하지 않습니다!)

방법?

Œ!ṗ⁸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)

여기 20이 있습니다. 나는 원래 이것을 당신과 독립적으로 썼지 만 꽤 비슷한 것으로 끝났고 순열 다이어 드 대신 카테 시안 힘을 사용하여 영감을 얻었으므로 아마도 그것을 향상시키는 데 사용하는 것이 가장 좋습니다. 설명에서 Graeco의 철자가 틀 렸습니다.
Nick Kennedy

고마워 Nick, 나는 우리가 평탄화 된 버전을 출력 할 수 있다는 것을 알지 못했다.
조나단 앨런


3

R , 164148 바이트

-주세페 덕분에 많은 바이트.

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

온라인으로 사용해보십시오!

극적으로 비효율적입니다-다른 무차별 대입 방식보다 훨씬 나쁘다고 생각합니다. 심지어 n=3TIO에서도 시간이 초과 될 수 있습니다. 다음n=3약 1 초 동안 작동하는 대체 버전 (155 바이트)입니다 .

거부에 의해 작동합니다. 이 함수 m는 과 사이의 임의의 정수 행렬을 그립니다 (각 정수를 정확히 번이나 다른 열에 표시하지 않고 코드의 속도를 설명하고 더 빠른 버전에서 변경된 유일한 것임). "latin"및 "greek"사각형 및 을 얻으려면이 함수를 두 번 호출하십시오 . 그런 다음 확인합니다.1nnlg

  1. all(1:n^2%in%(n*l+g-n)): 서로 다른 값 쌍이 있습니까?n2l × g
  2. 이다 lg라틴 방진?

행렬이 라틴 정사각형인지 확인하려면 함수를 사용하십시오 !. 위의 1 번 포인트가 검증되었으므로 각 정수 는 및 에서 각각 번 나타납니다 . 열 단위의 합계를 계산합니다 .이 합계는 각 정수가 각 열에 한 번만 나타나는 경우에만 동일하며 합계 값은 입니다. 이 모두 사실이라면 그 전치 후, 라틴 사각형입니다; 동일합니다 . 표준 편차를 계산하는 함수 는 벡터의 모든 값이 같은지 여부를 쉽게 확인할 수있는 방법입니다. 사소한 경우 및 에서는 작동하지 않으므로 OP에 따라 괜찮습니다.n2 n + 12 n = 0 n = 1lg2^l2n+12lt(l)lgsdn=0n=1

마지막 참고 사항 : R 코드 골프에서와 같이 종종 T초기화 된 변수를 사용하여 TRUE몇 바이트를 얻었습니다. 그러나 이것은 (parameter in ) TRUE의 정의에서 실제 값이 필요할 때 대신 대신 사용해야 한다는 것을 의미 합니다. 마찬가지로 부정과 다른 함수로 재정의 하고 있기 때문에 대신 대신 사용해야 했습니다 .mreplacesample1T!1-all(...)!all(...)


2

자바 스크립트 (ES6),  159 (147)  140 바이트

음수가 아닌 정수의 쌍 쌍의 플랫 배열을 반환합니다 .n×n

이것은 단순한 무차별 대입 검색이므로 매우 느립니다.

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=[])

온라인으로 사용해보십시오! (선점 출력)

댓글

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 ? (내 전화에서, 그것이 완전히 작동하는지 확실하지는 않습니다.)
Shaggy

나도 당신이 필요하다고 생각하지 않습니다 o. m
쉐기

@Shaggy 두 버전 모두 실패합니다 (아마도 실제로 역 추적 해야하는 첫 번째 크기이기 때문에 실제로 확인하지는 않았습니다). n=5
Arnauld

2

하스켈 , 207 (143) 233 바이트

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

온라인으로 사용해보십시오!

좋아, 나는 이번에 마침내 그것을 얻었다 고 생각한다. 그것은 TIO에서 n = 5, n = 6 시간 초과에서는 잘 작동하지만이 새로운 알고리즘은 매우 비효율적이며 기본적으로 작동하는 알고리즘을 찾을 때까지 모든 가능성을 검사하기 때문일 수 있습니다. 랩톱에서 n = 6을 실행하여 시간이 더 지나면 종료되는지 확인합니다.

이전 버전의 버그를 지적한 @someone에게 다시 감사합니다.


1
나는 Haskell을 모르지만 바닥 글의 "4"를 5로 변경하면 오류가있는 것 같습니다.이를 올바르게 호출합니까?
내 대명사는

@someone의 좋은 캐치, 나는 실제로 있는지 무엇을 잘못 여기려고하지, 이것은 걸릴 수 있습니다 ... 저는 그럴를 테스트 한해야 디버깅하는 동안
user1472751

1
여전히 버그가 있다고 생각합니다. n = 5로 실행하면 튜플 (1,1)이 두 번 나타납니다.
내 대명사는

@ 누군가,이 문제는 생각보다 훨씬 어렵습니다. 모든 제약 조건을 한 번에 잠글 수있는 신뢰할 수있는 방법을 찾을 수 없습니다. 내가 서로에게 집중하자마자 하나는 내 손에서 벗어납니다. 이 작업에 더 많은 시간을 할 수있을 때까지 비경쟁으로 표시하겠습니다. 내가해야
할만

1

C #을 520 506 494 484 바이트

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]+" ");}}

findinf 사각형의 알고리즘은 매우 간단합니다. ..... 무차별. 예, 멍청하지만 코드 골프는 프로그램 속도에 관한 것이 아닙니다.

더 짧게 만들기 전에 코드 :

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

이제 n = 3으로 테스트하려면 한 시간 정도 기다려야하므로 다른 버전이 있습니다.

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

업데이트 : "public"을 제거하는 것을 잊었습니다.

업데이트 : "시스템"을 사용했습니다. "시스템 사용"대신; 또한 Kevin Cruijssen 덕분 에 "args"대신 "a"를 사용했습니다.

업데이트 : gastropner누군가 덕분에 .


args할 수 있습니다 a:
케빈 Cruijssen

루프 각각은 변형 될 수 for(X = 0; X < Y; X++)for(X = Y; X-->0; )루프 당 바이트를 저장해야한다.
gastropner

1
Visual C # Interactive Compiler 를 사용해 보셨습니까 ? 바이트를 절약 할 수 있습니다. 익명 기능을 제출할 수도 있습니다. 바이트 i = 0를 정의 i하고 저장할 수도 있습니다 .
내 대명사는

@someone 의 제안에 따라 405 바이트 . 물론 TIO에서 60 초 후에 시간이 초과되지만 람다와 대화 형 컴파일러를 암시 적으로 사용하여 바이트를 절약합니다 System. 또한 일 if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)수 있습니다 if((m[i,j,k]=-~m[i,j,k]%n)>0).
케빈 크루이 ssen

@Kevin 나는 골프를 치려고하는 코드를 읽는 것을 정말로 느끼고 싶지 않습니다. 인쇄 부품이 제대로 작동합니까? 호출 내부의 문자열 Write에 추가 \n하여 바이트를 사용해야 하거나 바이트를 절약 할 수 있거나 그렇지 않은 것처럼 보입니다 . 배열을 직접 반환 할 수도 있다고 생각합니다.
내 대명사는

1

옥타브 , 182 바이트

무차별 강제 방법, TIO는 시간 초과를 유지하고 n = 3에 대한 출력을 얻기 위해 여러 번 실행해야했지만 이론적으로는 괜찮습니다. (1,2)와 같은 쌍 대신 1 + 2i와 같은 복잡한 접합체의 행렬을 출력합니다. 이것은 규칙을 약간 확장했을 수도 있지만 내 의견으로는 출력 요구 사항에 맞습니다. functino 선언에 따라 두 줄을 수행하는 더 좋은 방법이 있어야하지만 지금은 확실하지 않습니다.

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

온라인으로 사용해보십시오!


0

Wolfram Language (Mathematica) , 123 바이트

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

온라인으로 사용해보십시오!

TwoWayRule표기법 Transpose[...,2<->4]을 사용 하여 배열의 2 차원과 4 차원을 교체합니다. 그렇지 않으면 이것은 매우 간단합니다.

언 골프 드 :

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

파이썬 3 , 271 267 241 바이트

무차별 대입 방식 : Graeco-Latin 제곱을 찾을 때까지 쌍의 모든 순열을 생성합니다. n=3TIO 보다 더 큰 것을 생성하기에는 너무 느립니다 .

26 바이트 골프를 위한 alexz02 와 4 바이트 골프 를위한 ceilingcat 에 감사 합니다.

온라인으로 사용해보십시오!

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

설명:

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

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.