Graeco-Latin karesi oluşturun


24

sorumluluk reddi: Bruteforce çözümlerinden herhangi birinin farkında değilim

Bir Graeco-Latin kare aynı uzunlukta iki seti için, bir , bir düzenleme hücrelerinin birinci setinin bir elemanın çifti ve ikinci kümesinin bir element (kare şeklindeki bütün boyunca) benzersiz sahip, her biri öyle ki tüm ilk elemanlar ve çiftlerin tüm ikinci elemanlar sıra ve sütunlarında benzersizdir. Bir tahmin edebileceği olarak kullanılan en yaygın setleri, birinci olan Yunan ve Latin alfabe harfleri.nnxnn

İşte 4x4 Graeco-Latin karesinin bir resmi:görüntü tanımını buraya girin

Graeco-Latin kareleri göründüğü kadar kullanışlıdır ( Wikipedia makalesinde "deney tasarımı, turnuva planlaması ve sihirli kareler inşa etmekten bahseder"). Göreviniz pozitif bir tam sayı verilmiş olduğu bir oluşturmak için, Greko-Latin kare.nnxn

Giriş

Pozitif bir tamsayı ; Graeco-Latin karesinin var olduğu garanti edilir (yani, ).n>2nxnn6

Çıktı

İki boyutlu bir dizi olarak yan uzunluğu n olan bir Graeco-Latin karesi, bir dizi dizisi, düzleştirilmiş bir dizi veya doğrudan çıktısı.

notlar

  • Özellikle Yunanca ve Latin alfabelerini kullanmak zorunda değilsiniz; örneğin, pozitif tamsayı çiftlerinin çıkmasına da izin verilir.
  • Keyfi olarak uzatılamayan bir alfabe kullanmayı seçerseniz, (teorik olarak; evrenin ısı ölümünden önce kodunuzun bitmesi gerekmez) en az 20 maksimum kenar uzunluğu desteklemelisiniz.

Bu , yani en kısa kod kazanır!



Tek bir kare mi basmalıyız yoksa tüm olası kareleri bir liste olarak çıkarmamız uygun mudur?
Nick Kennedy,

Yanıtlar:


2

Jöle ,  21  20 bayt

Nick Kennedy sayesinde -1 (düz çıkış seçeneği, bir bayt tasarrufu ż"þ`ẎẎQƑ$Ƈ F€p`Z€QƑƇ )

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

Çevrimiçi deneyin! (Çok yavaş için4biz Kartezyen gücünü değiştirirseniz TIO üzerinde 60'lı yıllarda, ama,, Birleşimleri'ne,œc, o tamamlayacak - her ne kadar 5 kesinlikle olmaz!)

Nasıl?

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

İşte 20 . Aslında bunu kendinizden bağımsız olarak yazdım, ama oldukça benzer bir şeyle sonuçlandım ve sonra kartezyen gücü kullanımınız için bir permütasyon dyad yerine kullanmaktan ilham aldım. Notunuzda Graeco'yu yanlış yazdığınızı unutmayın.
Nick Kennedy,

Teşekkürler Nick, düzleştirilmiş bir versiyona çıktığımızın farkında değildim.
Jonathan Allan


3

R , 164 148 bayt

-many bayt Giuseppe sayesinde.

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

Çevrimiçi deneyin!

Dramatik olarak verimsiz - bence diğer kaba kuvvet yaklaşımlarından bile daha kötü. Yine de n=3, muhtemelen TIO'da zaman aşımına uğrayacak. İşten=3 yaklaşık 1 saniye için çalışan alternatif bir sürüm (155 bayt) .

m1nnlg

  1. all(1:n^2%in%(n*l+g-n))n2l x g
  2. Hangi lve glatin kareler?

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

Son bir not: R kodlu golfta sık sık, bir kaç bayt kazanmak için Tilklendirilen değişkeni kullandım TRUE. Ancak bu TRUE, m(parametre replacein sample) tanımındaki gerçek değere ihtiyacım olduğunda 1bunun yerine kullanmak zorunda kaldığım anlamına gelir T. Benzer şekilde, !olumsuzlamadan farklı bir işlev olarak yeniden tanımladığım için 1-all(...)yerine kullanmak zorunda kaldım !all(...).


2

JavaScript (ES6),  159 147  140 bayt

nxn

Bu basit bir kaba kuvvet araştırmasıdır ve bu nedenle çok yavaştır.

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

Çevrimiçi deneyin! (önceden belirlenmiş çıktı ile)

Yorumlananlar

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 ? (Telefonumda, tamamen çalıştığından emin değilim)
Shaggy

Senin de ihtiyacın olduğunu sanmıyorum o; Sadece dönebilirsiniz miçin sonunda 141
Shaggy

n=5

2

Haskell , 207 143 233 bayt

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

Çevrimiçi deneyin!

Tamam, sanırım sonunda bu sefer anladım. TIO'da n = 5, n = 6 kez iyi çalışıyor ancak bunun nedeni bu yeni algoritmanın KESİNLİKLE verimsiz olduğunun ve temelde işe yarayan bir tane bulana kadar tüm olasılıkları kontrol etmesi olabilir. Dizüstü bilgisayarımda şimdi n = 6 ile çalışıyorum.

Önceki sürümlerimdeki hataları gösterdiği için birisine tekrar teşekkür ederim


1
Haskell'i tanımıyorum, ancak altbilgideki "4" ü 5 olarak değiştirdiğimde bu benim için yanlış görünüyor. Bunu doğru şekilde çağırıyor muyum?
zamirim monicareinstate

@someone İyi yakalamak, bunu test etmeliydim. Aslında burada neyin yanlış gittiğinden emin değilim, bu hata ayıklamak biraz zaman alabilir
user1472751

1
Bunun hala bir hata olduğunu düşünüyorum; n = 5 için çalıştırıldığında, demet (1,1) iki kez görünür.
zamirim monicareinstate

@someone Adam, bu sorun düşündüğümden çok daha zor. Tüm kısıtlamaları bir kerede kilitlemenin güvenilir bir yolunu bulamıyorum. Bir başkasına odaklandığım anda başkası kavrayışımdan kayıyor. Bunun üzerinde çalışmak için biraz daha zaman bulana kadar şu an için rakipsiz olarak işaretleyeceğim. Yapmam gerektiği kadar iyi test etmediğim için üzgünüm
user1472751

1

C #, 520 506 494 484 bayt

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

Bir karede bulunan findinf algoritması çok basittir. Bu ... kaba kuvvet. Evet, aptalca, ama kod golf bir programın hızı ile ilgili değil, değil mi?

Kısaltmadan önce kod:

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

Şimdi, n = 3 ile test etmek istiyorsanız, bir saat kadar beklemeniz gerekecek, işte başka bir versiyon:

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

Güncelleme: "genel" kaldırmak için unuttum.

Güncelleme: "Sistem" kullandı. yerine "System ;; Ayrıca, Kevin Cruijssen sayesinde , "args" yerine "a" kullandı.

Güncelleme: gastropner ve biri sayesinde .


argsolabilir a:)
Kevin Cruijssen

Döngü için her dönüştürülmüş olabilir for(X = 0; X < Y; X++)için for(X = Y; X-->0; )döngü başına bir byte kaydetmek gerekir ki,.
gastropner

1
Visual C # Interactive Compiler'ı denediniz mi? Baytları kurtarabilir. Ayrıca anonim bir işlev de gönderebilirsiniz. Ayrıca bir bayt i = 0tanımını atayabilir ive kaydedebilirsiniz.
zamirim monicareinstate

Birinin önerisine göre 405 bayt . Elbette TIO'da 60 saniye sonra zaman aşımına uğrar, ancak bir lambda ve Etkileşimli Derleyici kullanarak örtük olarak bayt kazandırır System. Ayrıca, if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)olabilir if((m[i,j,k]=-~m[i,j,k]%n)>0).
Kevin Cruijssen

@Kevin Gerçekten golf oynamaya çalışırken bu kodu okumaktan hoşlanmıyorum. Baskı parçasının doğru çalıştığından emin misin? Aramanın içindeki dizeye Writeekleyerek kullanması veya baytları kurtarması gibi görünüyor \nya da aksi halde bozuldu. Doğrudan bir dizi de döndürebileceğinizi düşünüyorum.
zamirim monicareinstate

1

Octave , 182 bayt

Kaba kuvvet yöntemi, TIO zaman aşımına uğradı ve n = 3 için çıktı almak için birkaç kez çalıştırmam gerekti, ancak teorik olarak bu iyi olmalı. (1,2) gibi çiftlerin yerine, 1 + 2i gibi karmaşık konjugatların bir matrisini çıkarır. Bu kuralı biraz esnetiyor olabilir, ama bence stll çıktı gereksinimlerine uyuyor. Functino bildirgesinin altındaki iki çizgiyi yapmanın daha iyi bir yolu olmalı, ancak şu an emin değilim.

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

Çevrimiçi deneyin!


0

Wolfram Dili (Mathematica) , 123 bayt

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

Çevrimiçi deneyin!

Bir dizinin 2. ve 4. boyutlarını değiştirmek için TwoWayRulegösterimi kullanıyorum Transpose[...,2<->4]; Aksi takdirde bu oldukça basittir.

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

0

Python 3 , 271 267 241 bayt

Kaba kuvvet yaklaşımı: Bir Graeco-Latin karesi bulunana kadar çiftlerin tüm permütasyonlarını oluşturun. n=3TIO'dan daha büyük bir şey oluşturmak için çok yavaş .

Sayesinde alexz02 26 bayt golf için ve ceilingcat 4 bayt golf için.

Çevrimiçi deneyin!

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

Açıklama:

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

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.