【发布时间】:2013-10-06 21:20:35
【问题描述】:
我使用 Backtracking 方法在 C++ 中编写了 Knight's tour 算法。 但对于 n > 7(大于 7 x 7 棋盘),它似乎太慢或陷入无限循环。
问题是:这个算法的Time complexity是什么,我该如何优化它?!
骑士之旅问题可以表述如下:
给定一个有 n × n 个方格的棋盘,为骑士找到一条路径,该路径恰好访问每个方格一次。
这是我的代码:
#include <iostream>
#include <iomanip>
using namespace std;
int counter = 1;
class horse {
public:
horse(int);
bool backtrack(int, int);
void print();
private:
int size;
int arr[8][8];
void mark(int &);
void unmark(int &);
bool unvisited(int &);
};
horse::horse(int s) {
int i, j;
size = s;
for (i = 0; i <= s - 1; i++)
for (j = 0; j <= s - 1; j++)
arr[i][j] = 0;
}
void horse::mark(int &val) {
val = counter;
counter++;
}
void horse::unmark(int &val) {
val = 0;
counter--;
}
void horse::print() {
cout << "\n - - - - - - - - - - - - - - - - - -\n";
for (int i = 0; i <= size - 1; i++) {
cout << "| ";
for (int j = 0; j <= size - 1; j++)
cout << setw(2) << setfill ('0') << arr[i][j] << " | ";
cout << "\n - - - - - - - - - - - - - - - - - -\n";
}
}
bool horse::backtrack(int x, int y) {
if (counter > (size * size))
return true;
if (unvisited(arr[x][y])) {
if ((x - 2 >= 0) && (y + 1 <= (size - 1))) {
mark(arr[x][y]);
if (backtrack(x - 2, y + 1))
return true;
else
unmark(arr[x][y]);
}
if ((x - 2 >= 0) && (y - 1 >= 0)) {
mark(arr[x][y]);
if (backtrack(x - 2, y - 1))
return true;
else
unmark(arr[x][y]);
}
if ((x - 1 >= 0) && (y + 2 <= (size - 1))) {
mark(arr[x][y]);
if (backtrack(x - 1, y + 2))
return true;
else
unmark(arr[x][y]);
}
if ((x - 1 >= 0) && (y - 2 >= 0)) {
mark(arr[x][y]);
if (backtrack(x - 1, y - 2))
return true;
else
unmark(arr[x][y]);
}
if ((x + 2 <= (size - 1)) && (y + 1 <= (size - 1))) {
mark(arr[x][y]);
if (backtrack(x + 2, y + 1))
return true;
else
unmark(arr[x][y]);
}
if ((x + 2 <= (size - 1)) && (y - 1 >= 0)) {
mark(arr[x][y]);
if (backtrack(x + 2, y - 1))
return true;
else
unmark(arr[x][y]);
}
if ((x + 1 <= (size - 1)) && (y + 2 <= (size - 1))) {
mark(arr[x][y]);
if (backtrack(x + 1, y + 2))
return true;
else
unmark(arr[x][y]);
}
if ((x + 1 <= (size - 1)) && (y - 2 >= 0)) {
mark(arr[x][y]);
if (backtrack(x + 1, y - 2))
return true;
else
unmark(arr[x][y]);
}
}
return false;
}
bool horse::unvisited(int &val) {
if (val == 0)
return 1;
else
return 0;
}
int main() {
horse example(7);
if (example.backtrack(0, 0)) {
cout << " >>> Successful! <<< " << endl;
example.print();
} else
cout << " >>> Not possible! <<< " << endl;
}
上面例子 (n = 7) 的输出是这样的:
【问题讨论】:
-
您可能对this article 对构建大型游览感兴趣。
-
@PeterdeRivaz 谢谢,这很有趣,但无法从中获得足够的帮助,实现听起来太复杂了。
-
一般图的骑士之旅是 NP-hard,相当于访问图的每个顶点的哈密顿路径问题。然而,对于 8x8 标准棋盘的特殊情况,有已知的线性时间算法。这里描述了一种这样的算法:dl.acm.org/citation.cfm?id=363463。有趣的是,在预期的情况下,贪婪的启发式“我们移动马,以便我们总是前进到马向前移动最少的方格”实际上在实践中表现得非常好:en.wikipedia.org/wiki/Knight's_tour#Warnsdorff.27s_rule
-
我应该明确指出它不等同于哈密顿路径问题,但哈密顿路径问题减少到骑士的旅行问题,这使得骑士的旅行 NP 困难。
-
我为一个 8x8 板写了一个骑士巡回赛,它通过蛮力在 P100 上运行,平均 18 个小时的巡回赛,其中最长的将近 33 个小时。你在什么系统上用了多长时间?
标签: c++ optimization time-complexity backtracking knights-tour