1153 马的周游问题
标签: sicily algorithm 递归与回溯
原题中文大意
一个有限大小的棋盘上有一只马, 给出初始时马的位置, 找出一条马移动的路线,经过所有格子各一次.
算法思想
- 深搜
- 枚举马能走的所有格子, 直到找到一条路径覆盖所有格子
- 回溯
- 剪枝 (尽可能地减少搜索空间)
数据结构
用一个结构体来保存马每次走的一个格子的信息
struct nodes { /* data */ int x, y; // the coordinate of some grid int idx; // the index of (x, y), starting from 1 int countWays; // 从当前格子出发, 下一步可以走的格子数 }; // 比较函数, 用来排序 bool cmp(const nodes a, const nodes b) { return a.countWays < b.countWays; }
解题思路及算法描述
-
初始化搜索路径的起点
posIdx
, 和一个visited
数组(bool
类型)为false
, 及一个记录已经走过的格子的数组nums
和其个数的变量len
, -
将起点坐标传进
search
递归函数, 然后进行递归, 具体递归过程如下:
2.1 将visited[posIdx]
设为true
, 并记录该格子nums[len++] = posIdx
,
2.2 如果len==所有格子数
, 则打印路径, 并返回true
,
2.3 搜索posIdx
可走的格子validGrids
, 并根据alidGrid.countWays
对validGrids
进行升序排序(这里进行剪枝), 因为从可行格子较少的格子开始搜索, 会减少后续格子的搜索路径,
2.4 对validGrids
的每个格子进心递归(即调用search
函数), 并根据其返回值来确定是否结束回溯
2.5 进心回溯操作 >--len
和visited[posIdx]
设为false
, 并返回false
(这里因为从当前`posIdx出发进行搜索路径失败了), -
进行下一轮递归(即重复步骤1和2), 直到输入结束.
code
// Problem#: 1153 #include <iostream> #include <vector> #include <algorithm> #include <string> using namespace std; const int Row = 8; // x-coor const int Col = 8; // y-coor const int GridNum = Row * Col; int nums[GridNum + 1]; bool visited[GridNum + 1]; struct nodes { /* data */ int x, y; int idx; int countWays; }; bool cmp(const nodes a, const nodes b) { return a.countWays < b.countWays; } const int ValNum = 8; const int valXCoor[] = {-2, -2, -1, 1, 2, 2, 1, -1}; const int valYCoor[] = {-1, 1, 2, 2, 1, -1, -2, -2}; int getCountWays(const int posIdx) { bool isMode = (posIdx % Col) == 0; int x = posIdx / Col; x = isMode ? x - 1 : x; int y = (posIdx - 1) % Col; int count = 0; for(int i = 0; i < ValNum; i++) { int x2 = x + valXCoor[i]; int y2 = y + valYCoor[i]; int idx = x2 * Col + y2 + 1; bool flag = (x2 >= 0 && x2 < Row) && (y2 >= 0 && y2 < Col) && !visited[idx]; if(flag) { count++; } } return count; } std::vector<nodes> getValidGrids(const int posIdx) { bool isMode = (posIdx % Col) == 0; int x = posIdx / Col; x = isMode ? x - 1 : x; int y = (posIdx - 1) % Col; std::vector<nodes> validGrids; for(int i = 0; i < ValNum; i++) { int x2 = x + valXCoor[i]; int y2 = y + valYCoor[i]; int idx = x2 * Col + y2 + 1; bool flag = (x2 >= 0 && x2 < Row) && (y2 >= 0 && y2 < Col) && !visited[idx]; if(flag) { nodes grid; grid.x = x2; grid.y = y2; grid.idx = idx; grid.countWays = getCountWays(idx); validGrids.push_back(grid); } } sort(validGrids.begin(), validGrids.end(), cmp); return validGrids; } void printInfo() { int i; for(i = 0; i < Row * Col - 1; i++) { std::cout << nums[i] << " "; } std::cout << nums[i] << std::endl; } bool search(int posIdx, int& len) { visited[posIdx] = true; nums[len] = posIdx; len++; if(len == GridNum) { printInfo(); return true; } std::vector<nodes> validGrids = getValidGrids(posIdx); int size = validGrids.size(); for(int i = 0; i < size; i++) { if(search(validGrids[i].idx, len)) { return true; } } len--; visited[posIdx] = false; return false; } int main() { int posIdx; while(cin >> posIdx && posIdx != -1) { // fill(visited, false, GridNum * sizeof(bool)); // memset(visited, false, GridNum * sizeof(bool)); for(int i = 0; i <= GridNum; i++) { visited[i] = false; } int len = 0; search(posIdx, len); } return 0; }
测试数据
下面给出一些测试样例, 其中每个样例的第一行表示其输入, 第二行表示其输出
1. 2
2 17 11 1 18 3 9 26 41 58 52 62 56 39 24 7 13 23 8 14 4 10 25 19 29 12 6 16 31 48 63 46 40 55 61 51 57 42 36 21 15 5 22 32 38 53 59 49 34 28 45 30 47 64 54 60 43 37 20 35 50 33 27 44
- 4
4 10 25 42 57 51 61 55 40 23 8 14 24 7 13 3 9 19 2 17 34 49 59 44 50 33 27 12 6 16 31 48 63 46 29 39 56 62 52 58 41 35 18 1 11 5 15 21 38 32 22 28 45 60 54 64 47 30 36 53 43 26 20 37
-
5
5 15 32 47 64 54 48 63 53 59 49 34 17 2 12 6 16 31 14 8 23 40 55 38 21 4 10 25 19 9 3 13 7 24 30 20 37 22 39 56 62 45 60 50 33 27 44 29 46 61 51 57 42 36 26 11 1 18 28 43 58 41 35 52
-
10
10 4 14 8 23 6 16 31 48 63 53 59 49 34 17 2 12 29 19 25 42 57 51 61 55 40 46 56 62 52 58 41 35 50 33 18 1 11 5 15 32 47 64 54 60 43 26 9 3 20 37 27 44 38 21 36 30 13 7 24 39 22 28 45
-
30
30 15 32 47 64 54 48 63 53 59 49 34 17 2 12 6 16 31 14 8 23 40 55 38 21 4 10 25 19 9 3 13 7 24 39 56 62 45 60 50 33 18 1 11 5 22 28 43 58 41 26 20 37 27 44 29 35 52 46 61 51 36 42 57 -
20
20 3 9 26 41 58 52 62 56 39 24 7 13 23 8 14 4 10 25 19 2 17 11 1 18 35 29 12 6 16 31 48 63 46 40 55 61 51 57 42 36 21 15 5 22 32 38 53 59 49 34 28 45 30 47 64 54 37 43 60 50 33 27 44
-
21
21 4 10 25 42 57 51 61 55 40 23 8 14 24 7 13 3 9 19 2 17 34 49 59 44 27 33 50 60 54 64 47 32 15 30 36 53 38 48 63 46 31 16 6 12 29 39 56 62 45 28 22 5 11 1 18 35 20 37 52 58 41 26 43
-
17
17 2 12 6 16 31 48 63 53 59 49 34 51 57 42 25 10 4 14 8 23 40 55 61 46 56 62 52 58 41 26 9 3 13 7 24 39 29 19 36 21 15 32 38 44 27 33 50 35 18 1 11 5 22 28 45 30 20 37 47 64 54 60 43
9 -1
end
时间复杂度分析
总体来说, 对其进行剪枝后, 时间复杂度为O(n), 其中n为格子的总数
end