【问题标题】:Having difficulty in chess knights tour国际象棋骑士巡回赛遇到困难
【发布时间】:2019-02-04 14:42:14
【问题描述】:

我尝试使用回溯为骑士之旅问题编写代码。我的代码适用于 4x4 矩阵,但对于 8x8 矩阵,它不会在输出屏幕上显示任何内容。

我不知道我做错了什么。

这就是我的代码的工作方式:

如果所有方块都被访问过

print the solution

其他

  • 将下一步移动之一添加到解向量并递归 检查此举动是否会导致解决方案。 (一个骑士可以最大 八个动作。我们在这一步的 8 个动作中选择一个)。

  • 如果在上述步骤中选择的移动没有​​导致解决方案 然后从解决方案向量中删除此移动并尝试其他 替代动作。

  • 如果没有一个替代方案有效,则返回 false(返回 false 将在递归中删除先前添加的项目,如果为 false 由递归的初始调用返回然后“不存在解决方案”)

这是我写的代码:

#include<iostream>
using namespace std;
#define n 8
int safe(int c[n][n],int i, int j)
{
    if((i>=0&&i<n)&&(j>=0&&j<n))
    {
     if(c[i][j])
      return 0;
     else 
      return 1;
    }
    return 0;
}

    int knightstour(int c[n][n],int i,int j,int k)
  {
      if(k==n*n)
     {
      for(i=0;i<n;i++)
      {
          for(j=0;j<n;j++)
             cout<<c[i][j]<<"  ";
           cout<<endl;     
       }
       return 1;
      }
     else
     {
       c[i][j]=k;
          if(safe(c,i+2,j+1))
          {
              if(knightstour(c,i+2,j+1,k+1))
                return 1;
          }

          if(safe(c,i+2,j-1))
          {
              if(knightstour(c,i+2,j-1,k+1))
                return 1;
          }

          if(safe(c,i-2,j+1))
          {
              if(knightstour(c,i-2,j+1,k+1))
                return 1;
          }

          if(safe(c,i-2,j-1))
          {
              if(knightstour(c,i-2,j-1,k+1))
                return 1;
          }

          if(safe(c,i+1,j+2))
          {
           if(knightstour(c,i+1,j+2,k+1))
             return 1;
           }

          if(safe(c,i-1,j+2))
          {
           if(knightstour(c,i-1,j+2,k+1))
             return 1;
          }

          if(safe(c,i+1,j-2))
          {
           if(knightstour(c,i+1,j-2,k+1))
             return 1;
          }

          if(safe(c,i-1,j-2))
          {
           if(knightstour(c,i-1,j-2,k+1))
             return 1;
          }

        c[i][j]=0;
        return 0;
      }
   }
  int main()
 {
   int c[n][n]={0};
   if(!knightstour(c,0,0,0))
   cout<<"solution doesn't exist";
   return 1;
 }

【问题讨论】:

  • “它没有在输出屏幕上显示任何东西。” 所以计算还没有完成。测试的可能性很大,所以除非你有无限循环,否则检查每一个可能性都需要时间。
  • 啊,但是我的代码是否正确,我的意思是它能产生正确的输出吗?
  • @FeiXiang n 是宏,decl 是可能的
  • @138 哎呀,在顶部错过了。
  • main() 返回除 0 以外的任何值通常表示程序没有成功运行。

标签: c++ backtracking


【解决方案1】:

让我们暂时假设您的算法是正确的,因为它似乎产生了至少对n == 6 有用的东西:

 0  13  20  23  34  11  
21  30  35  12  19  24  
14   1  22  31  10  33  
29   4   7  16  25  18  
 6  15   2  27  32   9  
 3  28   5   8  17  26  

以下是使用各种 n 值运行代码的时钟时间结果:

===== 1  0m  0.001s
===== 2  0m  0.001s
===== 3  0m  0.003s
===== 4  0m  0.002s
===== 5  0m  0.070s
===== 6  0m 35.997s
===== 7  ...

你会注意到我没有那里还有n = 7的数字,它还在继续,5.5小时并且还在计数:-)

由于它会持续至少那么长(大约 330 分钟),我们可能可以使用回归分析(使用二次多项式仅使用大小为 5、6 且尚不完整的数据 7)(a)。根据这些计算,这个最小数字大约是 16.5 小时。

然而,即使它不是二次方,对于 6x6 板它跳到 36 秒并且对于 7x7 跳到(至少)5.5 小时这一事实意味着您使用的算法只是不规模化。所以您可能会发现它正在运行,您可能只需要等待一段时间。可能是 long 而 :-)


(a) 如果您有兴趣(或想检查/批评我的方法),这是我的分析。警告:前面的数学...

我们有数据集:

x (value of n)   y (seconds taken)
--------------   -----------------
      5                 0.07
      6                36.00
      7               600.00 (when it had been running ten minutes)

使用公式:

y = ax^2 + bx + c

我们最终得到联立方程:

  0.07 = 25a + 5b + c (1)
 36    = 36a + 6b + c (2)
600    = 49a + 7b + c (3)

减去对给我们:

(2) - (1):  35.93 = 11a + b (4)
(3) - (2): 564    = 13a + b (5)

(5) - (4): 528.07 = 2a

所以a = 264.035。将其替换回(5) 得到b = -2868.455 并将ab 替换为(3) 得到c = 7741.47。将这三个值放入方程 (1)(2)(3) 中得到预期值。

这是使用的方法(从我的高中时代开始),但是当然,如​​果600 数字发生变化,可以使用快速而肮脏的 Python 程序来更好地完成它:

import sys

y5 = 0.07 ; y6 = 36 ; y7 = int(sys.argv[1]) * 60

a = ((y7 - y6) - (y6 - y5)) / 2
b = (y7 - y6) - 13 * a
c = y7 - 49 * a - 7 * b

y8 = 64 * a + 8 * b + c
print(y8, y8 / 3600)

您可以运行它,提供大小 7 的当前值,它将推出最小数字(以秒和小时为单位)。

【讨论】:

  • 模式显然不是二次的。 (当 x=-b/2a 接近 5.432 时它有最小值?)递归算法往往需要指数时间,这更像您的数据。
  • @aschepler,是的,这只是一个初步计算。已更改文本以表明它可能不是实际公式。不管怎样,6x6 的大跳跃和 7x7 的大量跳跃意味着 8x8 很可能不会在宇宙热寂之前完成 :-)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多