码迷,mamicode.com
首页 > 其他好文 > 详细

拉丁方阵的一些思考

时间:2019-11-05 12:01:14      阅读:345      评论:0      收藏:0      [点我收藏+]

标签:pat   space   sla   注意   min   href   ati   最简   efi   

问题:

拉丁方阵(英语:Latin square)是一种 \(n × n\) 的方阵,在这种 $n × n \(的方阵里,恰有\) n $种不同的元素,每一种不同的元素在同一行或同一列里只出现一次。

\[ \begin{bmatrix} 1&2&3 \\\ 2&3&1 \\\ 3&1&2 \end{bmatrix} \begin{bmatrix}a&b&d&c \\\ b&c&a&d \\\ c&d&b&a \\\ d&a&c&b \end{bmatrix} \]

目前,没有公式可以计算 \(n × n\) 的拉丁方阵的数量。

标准型

当一个拉丁方阵的第一行与第一列的元素按顺序排列时,此为这个拉丁方阵的标准型。

下图即为一种标准型:

\(\left[ \begin{array}{cccc} 1 & 2 & 3 & 4 \\\ 2 & 1 & 4 & 3 \\\ 3 & 4 & 1 & 2 \\\ 4 & 3 & 2 & 1 \end{array} \right]\)

同型类别

许多对于拉丁方阵的运算都会产生新的拉丁方阵。例如说,交换拉丁方阵里的行、交换拉丁方阵里的列、或是交换拉丁方阵里的元素的符号,都会得到一个新的拉丁方阵。交换拉丁方阵里的行、交换拉丁方阵里的列、或是交换拉丁方阵里的元素的符号所得的新的拉丁方阵与原来的拉丁方阵称为同型(isotopic)。同型(isotopism)是一个等价关系,因此所有的拉丁方阵所成的集合可以分成同型类别(isotopic class)的子集合,同型的拉丁方阵属于同一个同型类别,而不属于同一个同型类别的拉丁方阵则不同型。

同型的计算

摘自爱问知识人

第一步

先设定一种最简单排法,假定1在第1排,第1列

第一排,\(1~n,\)
第二排,\(2~n,1,\)
第三排,\(3~n,1,2,\)
第四排,\(4~n,1,2,3,\)
\(n-1\)排,\(n-1,n,1~(n-2),\)
\(n\)排,\(n,1~(n-1),\)

第二步

把第\(2\)到第\(n\)排(整排)任意换位置重新排列,总满足要求,共有\((n-1)!\)种排法,

第三步

把第\(2\)到第\(n\)列(整列)任意换位置重新排列,总满足要求,共有\((n-1)!\)种排法,

第四步

把第\(1\)排的\(1\)分别可以换到第\(2~n\)列,算上前面第\(1\)列,共有\(n\)种排法,
所以,共有\(n\times (n-1)!\times (n-1)!=n!\times (n-1)!\)种排法。

end

即对于一个已知的一个拉丁方阵,同型的有\(n!\times (n-1)!\)

所谓的"已知解行列交换法"重复原因

摘自知乎

假设你先随便弄出一套满足的情况,然后你可以把行打乱随便排序,\(4!=24\),同理列也行,\(4!=24\)
两种情况合起来,\(24*24=576\)

不妨称上面的的解法为“已知解行列交换法”。
(1)对\(n\times n\)的表格,行列交换法的结果是\(s=n!\times n!\)。对于\(2\times 2\)\(3\times 3\)的表格时 \(s\)分别为\(4、36\),但实际上只有\(2、12\)种可能。于是最初猜测行列交换法会存在重复。
(2)为了验证行列交换法是否有重复解,我用程序对\(4\times 4\)的表格进行行列交换,去重后是\(144\)种,确实存在重复。
(3)那么正确结果是\(144\)吗? 接着用穷举法,列出所有解进行筛选,去重后是\(576\)种,可见,对已知解行列交换,无法涵盖所有的解。

以上几点证明行列交换法的思路是错误的(尽管它在\(4\times 4\)的时候得到了正确的结果)。

来说说自己的:

可先给行列标号:

若第一行为\(1,2,3,4……n\)
则列交换后可将第二行变得与第一行一致,且其余的新的每行都与之前某一行一致,则再在行交换后可得到与原来一致的方阵。共有\(n\)行,则有\(n\)种重复情况。

所以同样得到:对于一个已知的一个拉丁方阵,同型的有\(\frac{(n!^2)}{n}=n!\times(n-1)!\)

\(4\times 4\)做例子

比如已知一个拉丁方阵:

$ \begin{array}{}& 1 & 2 & 3 & 4 \end{array}\? \begin{array}{} \?1 \?2 \?3 \?4 \?\end{array}\left[ \begin{array}{} 1 & 2 & 3 & 4 \?2 & 3 & 4 & 1 \?3 & 4 & 1 & 2 \?4 & 1 & 2 & 3 \end{array} \right]$

先进行列交换后:

$ \begin{array}{}& 4 & 1 & 2 & 3 \end{array}\?\begin{array}{} \?1 \?2 \?3 \?4 \?\end{array}\left[ \begin{array}{} 4 & 1 & 2 & 3 \?1 & 2 & 3 & 4 \?2 & 3 & 4 & 1 \?3 & 4 & 1 & 2 \end{array} \right]$

再进行行交换后:

$ \begin{array}{}& 4 & 1 & 2 & 3 \end{array}\?\begin{array}{} \?2 \?3 \?4 \?1 \?\end{array} \left[ \begin{array}{} 1 & 2 & 3 & 4 \?2 & 3 & 4 & 1 \?3 & 4 & 1 & 2 \?4 & 1 & 2 & 3 \end{array} \right]$

行列标号的排列\(1,2,3,4/1,2,3,4\)变为\(2,3,4,1/4,1,2,3\),但拉丁方阵未变

对于一个能将第\(i\)行变得与第一行一致的列标号的排列,一定能找到唯一一个能使拉丁方阵不变的行标号的排列。

如对上述行列标号的排列,得到的拉丁方阵相同的排列\(4\)种。

\(1,2,3,4/1,2,3,4\)

\(2,3,4,1/4,1,2,3\)

\(3,4,1,2/3,4,1,2\)

\(4,1,2,3/2,3,4,1\)

标准型的计算

好像国际上也只能暴力找,最多到\(n=11\)

可以看看OEIS(整数数列线上大全)A000315

上一发自己写的代码:

#include<iostream>
#include<cstdio>
#include<cstring>
#include<cstdlib>
#include<algorithm>
#include<ctime> 
#define fr(x) freopen(#x ".in","r",stdin);freopen(#x ".out","w",stdout)
#define mem(a,b) memset(a,b,sizeof(a))
#define max(a,b) ((a)>(b)?(a):(b))
#define min(a,b) ((a)<(b)?(a):(b))
using namespace std;
const int MaxL=20,Max=1e5;
typedef long long ll;
int M[Max][MaxL];
int *m[MaxL];
int n,tot=0,numtot=0;
void dfs(int,int);
bool check(int);
void make();
int main()
{
//  fr(latin);
    int T[Max];
    scanf("%d",&n);
    for(int i=0;i<n;i++) T[i]=i+1;
    do
    {
        ++numtot;
        for(int j=0;j<n;j++) M[numtot][j]=T[j];
    }while(next_permutation(T,T+n)); 
    m[1]=&M[1][0];
    dfs(2,1);
    printf("%d\n",tot);
    fprintf(stderr,"%.3f s\n",clock()*1.0/CLOCKS_PER_SEC);
    return 0;
}
void dfs(int line,int num)
{
    if(line>n) return ++tot,make(),void();
    if(num>numtot) return;
    for(int i=num;i<=numtot;i++)
    {
        m[line]=&M[i][0];
        if(check(line)) dfs(line+1,i+1);
    }
//  while(!check(line)) m[line]=&M[++num][0];   
    return;
}
bool check(int line)
{
    for(int i=line-1;i;i--)
    {
        for(int j=0;j<n;j++) 
            if(!((*(m[line]+j))^(*(m[i]+j)))) return false;
    }
    return true;
}
void make()
{
    for(int i=1;i<=n;i++)
    {
        for(int j=0;j<n;j++) printf("%d ",(*(m[i]+j)));
        puts("");
    }
    puts("");
}

所有的拉丁方阵数量

为什么之前要说标准型

因为对于一个\(n\)阶拉丁方阵,不同的标准型之间不是同型,换句话说,只要知道\(n\)阶拉丁方阵的标准型个数,再乘上同型的个数,就是所有\(n\)阶拉丁方阵数量。

但国际上也只能暴力找,最多到\(n=11\)

PS:

用我写的程序暴力找\(n=7\)时的标准型个数,用时:

10001.097 s

约合\(2h50min\)(吓~~)

技术图片

高中数学

\(4×4\)的方格中,每个格子都填入\(1、2、3、4\)四个数字之一,要求每行、每列都没有重复数字,不同的填法共有(  )

A.\(24\)种 B.\(144\)种 C.\(432\)种 D.\(576\)

如果你已经知道拉丁方阵,并知道\(n=4\)时标准型的个数为\(4\)时,恭喜你,这道题秒杀~~

那如果不知道呢……

有比较常规的方法。

begin

我们可以一行一行的确定。

第一行没有限制,共\(4!=24\)种。

假设取出一组\([a,b,c,d]\)定为第一行。

根据错排问题的结论,第二行有\(9\)种。

那第三行呢?

我们发现事情并没有那么简单,在第二行不同的情况下,第三行可能有\(2\)种或\(4\)种……

怎么办?

只有分类讨论,看看是什么导致了\(2\)种或\(4\)种两种情况的产生。

第一行:\([a,b,c,d]\)

要构造出满足条件的第二行,第一个肯定不是\(a\),可以是\(b,c,d\)中的一种,假定选\(b\),那第二个呢?

可以是\(a,c,d\)中的一种,所以,区别开始了……

一、选\(a\)

如果这么选,那么这行就确定了:\([b,a,d,c]\)

观察一下特点:

\([a,b,c,d]\\ [b,a,d,c]\)

发现其实就是\(a,b\)交换,\(c,d\)交换。

把变换画成环就是这样:











我们给它起个名:对称

这下判断一下第三行。

第一二个只能放\(c,d\),第三四个只能放\(a,b\),而这两个内部交换位置得到的解也满足条件。

故这种情况下,第三行有\(2\times 2=4\) 种。

这种情况有多少种呢?

相当于从4个中选2个配对,但需注意的是,一旦选了一对,另一对也就确定了,故需除2去重。

\(\frac{C_4^2}{2}=3\)种。

二、选\(c\)\(d\)

其实这两个是等效的,假定选\(c\)

那第三个呢?

看似还可以选\(a,d\),其实只能选\(d\),为什么?

如果选\(a\),画成环:









\(d\)被孤立出来,而最后一个不能放\(d\),故不成立。

\(d\),画成环:











满足条件。

我们给它起个名:轮换

\([a,b,c,d]\\ [b,c,d,a]\)

这下判断一下第三行。

我们可以继续沿着这个环走,比如从\(b\)\(c\),其它依次变

得到一个解:\([c,d,a,b]\)

我们可以跳过一个走,比如从\(b\)\(d\),其它依次跳着变

得到另一个解:\([d,a,b,c]\)(相对于第二行不就是对称吗……)

只有两种。

故这种情况下,第三行有\(2\) 种。

这种情况有多少种呢?

这个整体的变换是个环,随便选一个开始,下一个有\(3\)种,再下一个有\(2\)种,都选定后这个环变换就确定了。

\(3\times 2=6\)种。

总结

总的有\(4!\times(\frac{C_4^2}{2}\times 4+3\times2\times2)=576\)种。

拉丁方阵的一些思考

标签:pat   space   sla   注意   min   href   ati   最简   efi   

原文地址:https://www.cnblogs.com/spaceskynet/p/11797562.html

(0)
(0)
   
举报
评论 一句话评论(0
登录后才能评论!
© 2014 mamicode.com 版权所有  联系我们:gaon5@hotmail.com
迷上了代码!