Hasilkan kotak Graeco-Latin

24

disclaimer: Saya tidak mengetahui adanya solusi non-bruteforce

Kotak Graeco-Latin adalah, untuk dua set dengan panjang yang sama , sebuah pengaturan sel, masing-masing berisi pasangan elemen set pertama dan elemen dari set kedua yang unik (melintasi seluruh kotak). sedemikian rupa sehingga semua elemen pertama dan semua elemen kedua dari pasangan unik di baris dan kolom mereka. Paling set yang umum digunakan adalah, sebagai salah satu bisa menebak, pertama huruf dari Yunani dan huruf Latin.nn×nn

Berikut adalah gambar kotak Graeco-Latin 4x4:masukkan deskripsi gambar di sini

Kotak Graeco-Latin sama bermanfaatnya dengan suara mereka ( artikel Wikipedia menyebutkan "desain eksperimen, penjadwalan turnamen, dan pembuatan kotak ajaib"). Tugas Anda adalah, diberi bilangan bulat positif , untuk menghasilkan Graeco-Latin.nn×n

Memasukkan

Bilangan bulat positif ; dijamin bahwa Graeco-Latin square (yaitu, ).n>2n×nn6

Keluaran

Sebuah persegi Graeco-Latin dengan panjang sisi n sebagai larik dua dimensi, larik larik, larik yang rata atau dihasilkan secara langsung.

Catatan

  • Anda tidak harus menggunakan huruf Yunani dan Latin secara khusus; misalnya, mengeluarkan pasangan bilangan bulat positif juga diizinkan.
  • Jika Anda memilih untuk menggunakan alfabet yang tidak dapat diperpanjang secara sewenang-wenang, Anda harus (secara teoritis; kode Anda tidak harus selesai sebelum kematian panas alam semesta) mendukung panjang sisi maksimal minimal 20.

Ini adalah , jadi kode terpendek menang!

kata ganti saya adalah monicareinstate
sumber
Tautan kotak pasir
kata ganti saya adalah monicareinstate
Apakah kita harus mengeluarkan satu kotak, atau apakah tidak apa-apa untuk menampilkan semua kotak yang mungkin sebagai daftar?
Nick Kennedy

Jawaban:

2

Jelly ,  21  20 byte

-1 berkat Nick Kennedy (opsi output datar memungkinkan byte penyimpanan )ż"þ`ẎẎQƑ$Ƈ F€p`Z€QƑƇ

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

Cobalah online! (Terlalu lambat untuk4dalam 60-an pada TIO, tetapi jika kita mengganti kekuatan Cartesian,, dengan Kombinasiœc, itu akan selesai - meskipun 5 pasti tidak akan!)

Bagaimana?

Œ!ṗ⁸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
sumber
Inilah 20 . Saya awalnya menulis ini secara independen dari Anda, tetapi berakhir dengan sesuatu yang sangat mirip, dan kemudian mengambil beberapa inspirasi dari penggunaan kekuatan Cartesian sebagai pengganti angka dua permutasi, jadi mungkin yang terbaik adalah menggunakannya untuk meningkatkan kualitas Anda. Perhatikan bahwa Anda salah mengeja Graeco dalam penjelasan Anda.
Nick Kennedy
Terima kasih Nick, saya tidak melihat kami diizinkan untuk mengeluarkan versi yang rata.
Jonathan Allan
3

05AB1E , 26 23 22 byte

-3 byte terima kasih kepada Emigna

-1 byte terima kasih kepada Kevin Cruijssen

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

Cobalah online!

Grimmy
sumber
1
n<ÝI‰bisa<Ýã
Emigna
... dan bisa L. Terima kasih!
Grimmy
1
ê}DIùQbisa ÙgQ}Puntuk menyimpan byte.
Kevin Cruijssen
@KevinCruijssen terima kasih! Saya mengeditnya.
Grimmy
3

R , 164 148 byte

-banyak byte berkat 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

Cobalah online!

Secara efisien tidak efisien - saya pikir ini bahkan lebih buruk daripada pendekatan brute force lainnya. Bahkan untuk n=3, itu mungkin akan habis pada TIO. Berikut adalah versi alternatif (155 byte) yang berfungsi n=3dalam waktu sekitar 1 detik.

m1nnlg

  1. all(1:n^2%in%(n*l+g-n))n2l × g
  2. adalah ldan gkotak latin?

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

Catatan terakhir: seperti yang sering dalam golf kode R, saya menggunakan variabel T, yang diinisialisasi sebagai TRUE, untuk mendapatkan beberapa byte. Tetapi ini berarti bahwa ketika saya membutuhkan nilai aktual TRUEdalam definisi m(parameter replacedalam sample), saya harus menggunakan 1alih-alih T. Demikian pula, karena saya mendefinisikan ulang !sebagai fungsi yang berbeda dari negasi, saya harus menggunakan 1-all(...)sebagai ganti !all(...).

Robin Ryder
sumber
2

JavaScript (ES6),  159 147  140 byte

n×n

Ini adalah pencarian brute force yang sederhana, dan karenanya sangat lambat.

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

Cobalah online! (dengan output prettified)

Berkomentar

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
sumber
144 ? (Di ponsel saya, jadi tidak sepenuhnya yakin itu berfungsi)
Shaggy
Saya pikir Anda juga tidak perlu o; Anda bisa kembali mpada akhir untuk 141
Shaggy
n=5
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]

Cobalah online!

OK, saya pikir saya akhirnya mendapatkannya kali ini. Ini berfungsi dengan baik untuk n = 5, n = 6 kali keluar pada TIO tapi saya pikir itu mungkin saja karena algoritma baru ini sangat tidak efisien dan pada dasarnya memeriksa semua kemungkinan sampai menemukan satu yang berfungsi. Saya menjalankan n = 6 di laptop saya sekarang untuk melihat apakah itu berakhir dengan lebih banyak waktu.

Sekali lagi terima kasih kepada @someone untuk menunjukkan bug di versi saya sebelumnya

pengguna1472751
sumber
1
Saya tidak tahu Haskell, tetapi ini keliru bagi saya ketika saya mengubah "4" di footer ke 5. Apakah saya menggunakan ini dengan benar?
kata ganti saya adalah monicareinstate
@ seseorang yang bagus, saya harus mengujinya. Saya sebenarnya tidak yakin apa yang salah di sini, ini mungkin perlu waktu untuk debug
user1472751
1
Saya pikir ini masih memiliki bug; ketika dijalankan untuk n = 5, tupel (1,1) muncul dua kali.
kata ganti saya adalah monicareinstate
@ seseorang, masalah ini jauh lebih sulit daripada yang saya kira. Saya tidak bisa menemukan cara yang dapat diandalkan untuk mengunci semua kendala sekaligus. Segera setelah saya fokus satu sama lain lolos dari genggaman saya. Saya akan menandainya sebagai non-bersaing untuk saat ini sampai saya dapat menemukan lebih banyak waktu untuk mengerjakan ini. Maaf untuk tidak menguji
selengkap yang
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]+" ");}}

Algoritma findinf a square sangat sederhana. Itu adalah ... bruteforce. Ya, itu bodoh, tetapi kode golf bukan tentang kecepatan suatu program, bukan?

Kode sebelum membuatnya lebih singkat:

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

Sekarang, jika Anda ingin mengujinya dengan n = 3 Anda akan harus menunggu seperti satu jam, jadi di sini adalah versi lain:

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

Perbarui: lupa menghapus "publik".

Pembaruan: digunakan "Sistem." alih-alih "menggunakan Sistem;"; Juga, terima kasih kepada Kevin Cruijssen , menggunakan "a" bukannya "args".

Perbarui: terima kasih kepada gastropner dan seseorang .

ettudagny
sumber
argsbisa a:)
Kevin Cruijssen
Setiap loop dapat ditransformasikan dari for(X = 0; X < Y; X++)ke for(X = Y; X-->0; ), yang seharusnya menghemat satu byte per loop.
gastropner
1
Sudahkah Anda mencoba Visual C # Interactive Compiler ? Itu bisa menghemat byte. Anda juga dapat mengirimkan fungsi anonim. Anda juga dapat menetapkan i = 0dalam definisi idan menyimpan byte.
kata ganti saya adalah monicareinstate
405 byte berdasarkan pada saran seseorang. Tentu saja waktu itu keluar setelah 60 detik pada TIO, tetapi tidak menyimpan byte dengan menggunakan lambda dan Compiler Interaktif dengan implisit System. Juga if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)bisa if((m[i,j,k]=-~m[i,j,k]%n)>0).
Kevin Cruijssen
@ Kevin Saya benar-benar merasa tidak suka membaca kode yang mencoba golf itu. Apakah Anda yakin bagian pencetakan berfungsi dengan baik? Sepertinya harus menggunakan Writeatau bisa menyimpan byte dengan menambahkan \nke string di dalam panggilan atau jika tidak rusak. Saya pikir Anda juga dapat mengembalikan array secara langsung.
kata ganti saya adalah monicareinstate
1

Oktaf , 182 byte

Metode brute force, TIO terus menghitung waktu dan saya harus menjalankannya beberapa kali untuk mendapatkan output untuk n = 3, tetapi secara teoritis ini seharusnya baik-baik saja. Alih-alih pasangan seperti (1,2) itu menghasilkan matriks konjugat kompleks seperti 1 + 2i. Ini mungkin sedikit meregangkan aturan, tetapi menurut saya itu tetap sesuai dengan persyaratan output. Harus ada cara yang lebih baik untuk melakukan dua baris di bawah pernyataan functino, tetapi saya tidak yakin saat ini.

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

Cobalah online!

OrangeCherries
sumber
0

Bahasa Wolfram (Mathematica) , 123 byte

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

Cobalah online!

Saya menggunakan TwoWayRulenotasi Transpose[...,2<->4]untuk menukar dimensi 2 dan 4 array; jika tidak, ini cukup mudah.

Tidak Disatukan:

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

Python 3 , 271 267 241 byte

Pendekatan brute-force: Hasilkan semua permutasi dari pasangan sampai sebuah kotak Graeco-Latin ditemukan. Terlalu lambat untuk menghasilkan sesuatu yang lebih besar dari n=3pada TIO.

Berkat alexz02 untuk bermain golf 26 byte dan untuk ceilingcat untuk bermain golf 4 byte.

Cobalah 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

Penjelasan:

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
Ketidakseimbangan
sumber
-26 byte
alexz02