Sicily 1153 马的周游问题

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;
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值