Generieren Sie ein Graeco-Latin-Quadrat

24

Haftungsausschluss: Mir sind keine Lösungen bekannt, die keine Bruteforce-Lösungen sind

Ein Graeco-Latin-Quadrat ist für zwei Sätze gleicher Länge n eine n×n Anordnung von Zellen, die jeweils ein eindeutiges (über das gesamte Quadrat verteiltes) Paar eines Elements des ersten Satzes und eines Elements des zweiten Satzes enthalten, z dass alle ersten Elemente und alle zweiten Elemente der Paare in ihrer Zeile und Spalte eindeutig sind. Die gebräuchlichsten Mengen sind, wie man ahnen könnte, die ersten Buchstaben des griechischen und des lateinischen Alphabets.n

Hier ist ein Bild eines 4x4 Graeco-Latin Quadrats:Bildbeschreibung hier eingeben

Graeco-Latin-Quadrate sind so nützlich wie sie klingen (der Wikipedia-Artikel erwähnt "Design von Experimenten, Turnierplanung und Konstruktion magischer Quadrate"). Ihre Aufgabe ist es, mit einer positiven ganzen Zahl ein Graeco-Latin-Quadrat zu generieren .nn×n

Eingang

Eine positive ganze Zahl ; Es ist garantiert, dass ein Graeco-Latin-Quadrat existiert (also ).n>2n×nn6

Ausgabe

Ein Graeco-Latin-Quadrat mit der Seitenlänge n als zweidimensionales Array, Array von Arrays, abgeflachtes Array oder direkt ausgegeben.

Anmerkungen

  • Sie müssen das griechische und das lateinische Alphabet nicht speziell verwenden. Beispielsweise ist die Ausgabe von Paaren positiver Ganzzahlen ebenfalls zulässig.
  • Wenn Sie ein Alphabet verwenden, das nicht willkürlich erweitert werden kann, müssen Sie (theoretisch: Ihr Code muss nicht vor dem Hitzetod des Universums fertig sein) eine maximale Seitenlänge von mindestens 20 unterstützen.

Das ist , also gewinnt der kürzeste Code!

Mein Pronomen ist monicareinstate
quelle
Sandbox-Link
mein Pronomen ist monicareinstate
Müssen wir ein einzelnes Quadrat ausgeben, oder ist es in Ordnung, alle möglichen Quadrate als Liste auszugeben?
Nick Kennedy

Antworten:

2

Jelly ,  21 bis  20 Bytes

-1 dank Nick Kennedy (Flat-Output-Option ermöglicht eine Byte-Speicherung von ż"þ`ẎẎQƑ$Ƈ F€p`Z€QƑƇ )

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

Probieren Sie es online! (Für4TIO in den 60ernzu langsam, aber wenn wir die kartesische Potenzdurch Combinationsersetzen,œcwird sie vervollständigt - obwohl 5 sicherlich nicht!)

Wie?

Œ!ṗ⁸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)
Jonathan Allan
quelle
Hier ist eine 20 . Ich habe das ursprünglich unabhängig von dir geschrieben, aber am Ende etwas ziemlich Ähnliches gefunden und mich dann von deiner Verwendung der kartesischen Kraft anstelle einer Permutations-Dyade inspirieren lassen. Daher ist es wahrscheinlich am besten, sie zu verwenden, um deine zu verbessern. Beachten Sie, dass Sie Graeco in Ihrer Erklärung falsch geschrieben haben.
Nick Kennedy
Danke Nick, ich habe nicht bemerkt, dass wir eine abgeflachte Version ausgeben dürfen.
Jonathan Allan
3

05AB1E , 26 23 22 Bytes

-3 Bytes dank Emigna

-1 Byte dank Kevin Cruijssen

Lãœ.ΔIôDζ«D€í«ε€нÙgQ}P

Probieren Sie es online!

Grimmig
quelle
1
n<ÝI‰ kann sein <Ýã
Emigna
... und kann sein L. Vielen Dank!
Grimmy
1
ê}DIùQkann sein ÙgQ}P, ein Byte zu speichern.
Kevin Cruijssen
@ KevinCruijssen danke! Ich habe das in.
Grimmy
3

R , 164 148 Bytes

-viele Bytes dank 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

Probieren Sie es online!

Dramatisch ineffizient - ich denke, es ist noch schlimmer als andere Brute-Force-Ansätze. Selbst für n=3TIO wird es wahrscheinlich eine Zeitüberschreitung geben. Hier ist eine alternative Version (155 Bytes), die n=3in etwa 1 Sekunde funktioniert .

Arbeitet durch Ablehnung. Die Funktion mzeichnet eine zufällige Ganzzahlmatrix zwischen 1 und n (ohne zu erzwingen, dass jede Ganzzahl genau erscheint)nlg

  1. all(1:n^2%in%(n*l+g-n)): Gibt es n2 verschiedene Wertepaare inl × g
  2. sind lund glateinische Quadrate?

!nlg2^l2n+1-2lt(l)lgsdn=0n=1

Eine letzte Anmerkung: Wie so oft beim R-Code-Golf habe ich die Variable T, die initialisiert wird TRUE, verwendet, um ein paar Bytes zu gewinnen. Das bedeutet aber, dass ich, als ich den tatsächlichen Wert TRUEin der Definition von m(parameter replacein sample) benötigte, 1anstelle von verwenden musste T. Ebenso musste ich, da ich !als eine von der Negation verschiedene Funktion neu definiere , 1-all(...)statt verwenden !all(...).

Robin Ryder
quelle
2

JavaScript (ES6),  159 147  140 Byte

n×n Paaren nicht negativer Ganzzahlen zurück.

Dies ist eine einfache Brute-Force-Suche und daher sehr langsam.

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

Probieren Sie es online!(mit schönem Ausgang)

Kommentiert

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 = []
Arnauld
quelle
144 ? (Auf meinem Handy, also nicht ganz sicher, ob es funktioniert)
Shaggy
Ich glaube, du brauchst es oauch nicht. Sie können nur mam Ende für 141
Shaggy
n=5
2

Haskell , 207 143 233 Bytes

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

Probieren Sie es online!

OK, ich glaube, ich habe es dieses Mal endlich geschafft. Es funktioniert gut für n = 5, n = 6 mal auf TIO, aber ich denke, das könnte nur daran liegen, dass dieser neue Algorithmus UNGLAUBLICH ineffizient ist und im Grunde alle Möglichkeiten überprüft, bis er eine findet, die funktioniert. Ich starte jetzt n = 6 auf meinem Laptop, um zu sehen, ob es mit etwas mehr Zeit endet.

Nochmals vielen Dank an @someone für den Hinweis auf die Fehler in meinen vorherigen Versionen

user1472751
quelle
1
Ich kenne Haskell nicht, aber das scheint mir ein Fehler zu sein, wenn ich die "4" in der Fußzeile auf 5 ändere. Rufe ich das richtig auf?
Mein Pronomen ist monicareinstate
@someone Guter Fang, ich hätte das testen sollen. Ich bin mir eigentlich nicht sicher, was hier falsch läuft. Das kann eine Weile dauern, bis das Debugging durchgeführt wird
user1472751
1
Ich denke, das hat immer noch einen Bug. Wenn für n = 5 ausgeführt wird, erscheint das Tupel (1,1) zweimal.
Mein Pronomen ist monicareinstate
@someone Man, dieses Problem ist viel schwieriger als ich dachte. Ich kann einfach keinen zuverlässigen Weg finden, um alle Einschränkungen auf einmal zu sperren. Sobald ich mich aufeinander konzentriere, rutscht einer aus meinem Griff. Ich werde vorerst als nicht konkurrierend markieren, bis ich etwas mehr Zeit finde, um daran zu arbeiten. Entschuldigung, dass ich nicht so gründlich getestet habe, wie ich sollte
user1472751
1

C #, 520 506 494 484 Bytes

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

Der Algorithmus zum Finden eines Quadrats ist sehr einfach. Es ist ... Bruteforce. Ja, es ist dumm, aber beim Codegolf geht es nicht um die Geschwindigkeit eines Programms, oder?

Der Code vor der Verkürzung:

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

Wenn Sie es nun mit n = 3 testen möchten, müssen Sie eine Stunde warten. Hier ist eine andere Version:

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

Update: vergessen, "public" zu entfernen.

Update: verwendet "System". anstelle von "using System;"; Dank Kevin Cruijssen wurde auch "a" anstelle von "args" verwendet.

Update: Danke an Gastropner und jemanden .

ettudagny
quelle
argskann sein a:)
Kevin Cruijssen
Jede for-Schleife könnte von for(X = 0; X < Y; X++)nach transformiert werden for(X = Y; X-->0; ), wodurch ein Byte pro Schleife eingespart werden sollte.
Gastropner
1
Haben Sie den interaktiven Visual C # -Compiler ausprobiert ? Es kann Bytes sparen. Sie können auch eine anonyme Funktion einreichen. Sie können auch ein Byte i = 0definieren iund speichern.
Mein Pronomen ist monicareinstate
405 Bytes basierend auf @ jemandem Vorschlag. Natürlich läuft es nach 60 Sekunden bei TIO ab, aber es spart Bytes, wenn ein Lambda und der interaktive Compiler implizit verwendet werden System. Auch if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)kann if((m[i,j,k]=-~m[i,j,k]%n)>0).
Kevin Cruijssen
@ Kevin Ich habe nicht wirklich Lust, diesen Code zu lesen, um Golf zu spielen. Sind Sie sicher, dass der Druckteil richtig funktioniert? Es sieht so aus, als ob es entweder WriteBytes verwenden sollte oder speichern könnte, indem \nes der Zeichenfolge innerhalb des Aufrufs hinzugefügt wird , oder es ist auf andere Weise defekt. Ich denke, Sie können ein Array auch direkt zurückgeben.
Mein Pronomen ist monicareinstate
1

Oktave , 182 Bytes

Bei der Brute-Force-Methode läuft TIO immer aus und ich musste es einige Male ausführen, um die Ausgabe für n = 3 zu erhalten, aber theoretisch sollte dies in Ordnung sein. Anstelle von Paaren wie (1,2) wird eine Matrix komplexer Konjugate wie 1 + 2i ausgegeben. Dies könnte die Regel ein wenig ausdehnen, aber meiner Meinung nach entspricht es nicht den Ausgabeanforderungen. Es muss einen besseren Weg geben, die beiden Zeilen unter der Funktino-Deklaration zu machen, aber ich bin mir im Moment nicht sicher.

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

Probieren Sie es online!

OrangeCherries
quelle
0

Wolfram Language (Mathematica) , 123 Byte

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

Probieren Sie es online!

Ich benutze die TwoWayRuleNotation Transpose[...,2<->4], um die 2. und 4. Dimension eines Arrays zu vertauschen. ansonsten ist das ziemlich einfach.

Ungolfed:

(* 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];
Lirtosiast
quelle
0

Python 3 , 271 267 241 Bytes

Brute-Force-Ansatz: Generieren Sie alle Permutationen der Paare, bis ein Graeco-Latin-Quadrat gefunden wird. Es ist zu langsam, um etwas Größeres als n=3bei TIO zu generieren .

Danke an alexz02 für das Golfen mit 26 Bytes und an ceilingcat für das Golfen von 4 Bytes.

Probieren Sie es online!

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

Erläuterung:

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
OOBalance
quelle
-26 bytes
alexz02