1153. 马的周游问题
Constraints
Time Limit: 1 secs, Memory Limit: 32 MB , Special Judge
Description
和题目C同样的任务,这里只是把棋盘扩大到标准的国际象棋。对这样一个8 * 8的棋盘用同样的方法编号如下:
1 2 3 4 5 6 7 8
9 10 11 12 13 14 15 16
17 18 19 20 21 22 23 24
25 26 27 28 29 30 31 32
33 34 35 36 37 38 39 40
41 42 43 44 45 46 47 48
49 50 51 52 53 54 55 56
57 58 59 60 61 62 63 64
Input
输入有若干行。每行一个整数N(1<=N<=64),表示马的起点。最后一行用-1表示结束,不用处理。
Output
对输入的每一个起点,求一条周游线路。对应地输出一行,有64个整数,从起点开始按顺序给出马每次经过的棋盘方格的编号。相邻的数字用一个空格分开。
Sample Input
4-1
Sample Output
注意:如果起点和输入给定的不同,重复多次经过同一方格或者有的方格没有被经过,都会被认为是错误的。
Problem Source
ZSUACM Team Member
一开始实现方法是根据判断出的区域(左上、右上、左下、右下)未访问格子数目,来对下一扩展节点排序,从而减少时间,但是还是超时- -,遂放弃。尝试通过先扩展子节点少的节点来减少时间,成功。
为什么要先扩展子节点少的节点呢?因为这样可以先把没前途的点先走完,因为它没前途,所以从其它点通过它再遍历全图的可能性就太低噜。
#include <iostream>
#include <algorithm>
#include <list>
#include <vector>
#include <string.h>
using namespace std;
// 方便回溯的访问数组
int visited[35][35] = {0};
// 确定移动方向的增量数组
const int moveRow[8] = {2, 1, -1, -2, -2, -1, 1, 2};
const int moveCol[8] = {1, 2, 2, 1, -1, -2,-2,-1};
// 记录移动路径
vector<int> sequence;
// 步数纪录
int step_count = 0;
// 定义一!匹!马!
struct horse{
int row;
int col;
int pos;
int children_count;
};
bool valid(int col, int row) {
return (col >= 1 && col <= 8) && (row >= 0 && row <= 7);
}
bool cmp(horse a, horse b) {
return a.children_count < b.children_count;
}
bool dfs(int current) {
// 到达64步,说明有解,返回真
if(step_count == 64) return true;
// 为方便实用增量数组,将编好序号的整数分解为行、列信息
vector<horse> validDirections;
for(int i = 0; i < 8; i++) {
horse tmp;
int col = current%8;
int row = (int)(((double)current-0.5)/8);
// 注意处理最左一行
if(col == 0) col = 8;
// 每一个马最多有8个方向
tmp.children_count = 0;
// 设置下一步走哪里
tmp.row = row + moveRow[i];
tmp.col = col + moveCol[i];
// 如果下一步是有效的
if(valid(tmp.col, tmp.row) && visited[tmp.row][tmp.col] == 0) {
for(int j = 0; j < 8; j++) {
int nextnextRow = tmp.row + moveRow[j];
int nextnextCol = tmp.col + moveCol[j];
if(valid(nextnextCol, nextnextRow) && visited[nextnextRow][nextnextCol] == 0)
tmp.children_count++;
}
tmp.pos = tmp.row* 8 + tmp.col;
validDirections.push_back(tmp);
}
}
sort(validDirections.begin(), validDirections.end(), cmp);
for(int k = 0; k < validDirections.size(); k++) {
visited[validDirections[k].row][validDirections[k].col] = 1;
step_count++;
sequence.push_back(validDirections[k].pos);
if(dfs(validDirections[k].pos)) return true;
// 回溯,将更改过的全局变量全部置为搜索之前的
else {
visited[validDirections[k].row][validDirections[k].col] = 0;
step_count--;
sequence.pop_back();
}
}
return false;
}
int main() {
int N;
while(cin >> N && N != -1) {
memset(visited, 0, sizeof(visited));
sequence.clear();
step_count = 1;
int tmpCol = N % 8;
if(tmpCol == 0) tmpCol = 8;
visited[(int)((N-0.5)/8)][tmpCol] = 1;
sequence.push_back(N);
if(dfs(N)) {
for(int i = 0; i < sequence.size(); i++) cout << sequence[i] << " ";
cout << endl;
}
}
return 0;
}