Graeco-Latin正方形を生成する


24

免責事項:私は、非総当たり的な解決策を知りません

Graeco-Latin正方形は、同じ長さ 2つのセットの場合、のセルの配置であり、各セルには、最初のセットの要素と2番目のセットの要素の一意の(正方形全体)ペアが含まれます。そのため、ペアのすべての最初の要素とすべての2番目の要素は、行と列で一意です。使用される最も一般的なセットは、推測できるように、ギリシャ語とラテン語のアルファベットの最初の文字です。nn×nn

これは、4x4のグレコラテン広場の写真です。ここに画像の説明を入力してください

Graeco-Latinの正方形は、見た目と同じくらい便利です(Wikipediaの記事では、「実験の設計、トーナメントのスケジューリング、および魔方陣の構築」に言及しています)。あなたのタスクは、正の整数与えられ、グレコ-ラテン二乗を生成します。nn×n

入力

正の整数 ; Graeco-Latin正方形が存在することが保証されます(つまり、)。n>2n×nn6

出力

二次元配列、配列の配列、平坦化された配列、または直接出力としての辺の長さnのGraeco-Latin正方形。

ノート

  • ギリシャ語とラテン語のアルファベットを特に使用する必要はありません。たとえば、正の整数のペアを出力することもできます。
  • 任意に拡張できないアルファベットを使用する場合、(理論的には、宇宙の熱死の前にコードを終了する必要はありません)少なくとも20の最大辺の長さをサポートする必要があります。

これはなので、最短のコードが優先されます!



単一の正方形を出力する必要がありますか、それともすべての可能な正方形をリストとして出力しても大丈夫ですか?
ニックケネディ

回答:


2

ゼリー 21  20 バイト

-1 Nick Kennedyに感謝(フラット出力オプションによりż"þ`ẎẎQƑ$Ƈ バイト保存が可能F€p`Z€QƑƇ

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

オンラインでお試しください!4TIOで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のスペルを間違えていることに注意してください。
ニックケネディ

ニックのおかげで、フラット化されたバージョンの出力が許可されていることに気付かなかった
ジョナサンアラン

3

05AB1E26 23 22バイト

エミグナのおかげで-3バイト

-1バイト、Kevin Cruijssenに感謝

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

オンラインでお試しください!


1
n<ÝI‰することができます<Ýã
エミグナ

...そしてすることができますL。ありがとう!
グリムミー

1
ê}DIùQÙgQ}Pバイトを保存することができます。
ケビンクルーッセン

@KevinCruijssenありがとう!私はでそれを編集した。
Grimmy

3

R164 148バイト

-ジュゼッペのおかげで多くのバイト。

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=3おそらくTIOでタイムアウトになります。ここために働く代替バージョン(155バイト)でありn=3、約1秒では。

m1nnlg

  1. all(1:n^2%in%(n*l+g-n))n2l × g
  2. あるlgラテン方格?

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

最後の注意:RコードゴルフではよくあることですがT、変数を使用して、として初期化しTRUE、数バイトを取得しました。私は実際の値を必要なときにでも、この手段というTRUEの定義にm(パラメータreplacesample)、私が使用していた1代わりにT。同様に、!否定とは異なる関数として再定義しているため、の1-all(...)代わりに使用する必要がありました!all(...)


2

JavaScript(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?(私の電話では、完全に機能するかどうか
シャギー

私もあなたが必要だとは思わないo。あなただけ返すことができるmために最後に141
シャギー

n=5

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良いキャッチ、私はthat.I'mが実際に確認してください、何が間違ってここに起こっているのではないテストしてみなければならない、これはデバッグにしばらく時間がかかるかもしれません
user1472751

1
これにはまだバグがあると思います。n = 5で実行すると、タプル(1,1)が2回表示されます。
私の代名詞は

@someone Man、この問題は思ったよりずっと難しい。一度にすべての制約をロックダウンする信頼できる方法が見つかりません。私がお互いに焦点を合わせるとすぐに、私は把握できなくなります。これに取り組む時間をもう少し見つけることができるまで、私は今のところ非競合としてマークします。私が持っているはずのように徹底的にテストしていないため申し訳ありません
user1472751

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 a squareのアルゴリズムは非常に簡単です。それは...総当たりです。ええ、それは馬鹿げていますが、コードゴルフはプログラムのスピードについてではありませんよね?

短くする前のコード:

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でテストしたい場合、1時間ほど待たなければならないので、別のバージョンを次に示します。

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ループはからfor(X = 0; X < Y; X++)に変換でき、ループfor(X = Y; X-->0; )ごとに1バイト節約できます。
ガストロプナー

1
Visual C#Interactive Compilerを試しましか?バイトを節約できます。匿名関数を送信することもできます。また、バイトをi = 0定義して割り当て、i保存することもできます。
私の代名詞は、

@someoneの提案に基づく405バイト。もちろん、TIOで60秒後にタイムアウトになりますが、ラムダとInteractive Compilerとimplicitを使用してバイトを節約しますSystem。また、if((m[i,j,k]=(m[i,j,k]+ 1) % n)!=0)することができますif((m[i,j,k]=-~m[i,j,k]%n)>0)
ケビンクルーッセン

@Kevinゴルフをしようとしてそのコードを読んでみたいとは本当に思いません。印刷部分は正常に機能しますか?呼び出し内の文字列にWrite追加\nすることでバイトを使用するか、バイトを節約できるか、または壊れているようです。配列を直接返すこともできると思います。
私の代名詞は

1

オクターブ、182バイト

ブルートフォース方式、TIOはタイムアウトし続け、n = 3の出力を得るために何度も実行する必要がありましたが、理論的にはこれで問題ありません。(1,2)のようなペアの代わりに、1 + 2iのような複素共役の行列を出力します。これは少しルールを引き延ばすかもしれませんが、私の意見では、出力要件に適合します。ただし、functino宣言の下で2行を実行するより良い方法が必要ですが、現時点ではわかりません。

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言語(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

Pythonの3271の 267 241バイト

ブルートフォースアプローチ:グレーコラテン方格が見つかるまで、ペアのすべての順列を生成します。n=3TIO よりも大きいものを生成するには遅すぎます。

おかげalexz02 26バイトのゴルフ用とにceilingcat 4バイトのゴルフのため。

オンラインでお試しください!

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.