递归循环和 DFS

Recursive cycles and DFS

我的任务是使用深度优先搜索找到所有大小为 N 的拉丁方块。我需要检查正方形大小 N 的所有可能变体是否是拉丁语。它可以通过从 1 到 N 的 N * N 嵌套循环 'for' 来完成(位置(0,0)的第一个循环,位置(0,1)的第二个嵌套等等)。显然,它只适用于某些特定的 N₀。我需要一个更通用的解决方案,它可以适用于随机 N,所以我想编写一个递归过程,根据输入的 N 来模仿这些 N * N 循环。

现在我相信,我有办法了。

好的,似乎有效。希望有人会发现它有用。

更新:删除无用的一维数组,现在似乎工作得更快(正如我计算的(但未通过实验检查),对于 N=4,以前的方法将花费 ≈218.07 小时)。

Upd2:从在 LS 检查中使用标志和 'if' 移动到标签,似乎更快(两次实验平均 271.172 秒找到大小为 4 的 LS(检查 4294967296 变体)与之前的 4041.453 秒相比更新)。

procedure filling(str, col: Integer);
var
I, I1, J1, a, b, fl: Integer;
label
skip;

begin
 for I := 1 to N do begin
  lat_sq[str, col]:=I;
  if (col<N-1) then filling(str, col+1)
   else if  (str<N-1) then filling(str+1, 0)
  else if (str=N-1) and (col=N-1) then begin
  

   
   for I1 := 0 to N-1 do
    for J1 := 0 to N-1 do begin

      for a := 0 to N-1 do
       if (a<>I1) and (lat_sq[I1, J1]=lat_sq[a, J1]) then goto skip; 
      for b := 0 to N-1 do
       if (b<>J1) and (lat_sq[I1, J1]=lat_sq[I1, b]) then goto skip; 
    end;

   
    for I1 := 0 to N-1 do begin
     for J1 := 0 to N-1 do
     write(lat_sq[I1, J1]);
     writeln;
    end;

    writeln;

  
   skip:
  end;
 end;

end; 

upd3: 决定保留以前的代码,因为这个新代码有另一种 LS 检查方法:如果无法填充检查的单元格,它会移动到另一个循环进行 I 迭代。在不到 1 毫秒的时间内找到 N=4 的 LS,在 1468.687 秒内找到 N=6,更高的 N 需要无意义的时间。 N_1表示N-1。

upd4:删除无用的额外检查,如果发现 N=6 的 LSs 持续 1410.719 秒。

procedure filling(str, col: Integer);
var
I, I1, J1, a, b, fl: Integer;
label
skip;

begin
 for I := 1 to N do begin

  lat_sq[str, col]:=I;

  fl:=1;

  for I1 := 0 to str-1 do
   if (lat_sq[I1, col]=lat_sq[str, col]) then goto skip;

  for J1 := 0 to col-1 do
   if (lat_sq[str, J1]=lat_sq[str, col]) then  goto skip; 



  if (col<n_1) then filling(str, col+1)
   else if (str<n_1) then filling(str+1, 0)




   else begin
    
    for I1 := 0 to N-1 do begin
     for J1 := 0 to N-1 do
     write(lat_sq[I1, J1]);
     writeln;
    end;

    writeln;
    

    inc(count);

   end; 
  skip:
 end;

end;

首先,你需要一个排列生成器,比如 Heap 的算法:

https://www.geeksforgeeks.org/heaps-algorithm-for-generating-permutations/

每行以 1、2、...、N 开头。

对于我=到N 对第 i 行进行排列,并检查其中没有重复 任何专栏。我在那里,采取这一行的下一个排列。 如果没有重复,就取下一行(next i)。