DFS解决骑士林克的怜悯(1)

问题描述

林克驰骋在海拉鲁大陆的平原上无比自由,他想起二维空间中的国际象棋同伴,回想起自己也活在2D世代的局限,心生怜悯。

那些骑士,永远被局限在8×8的棋盘之内厮杀,他们的世界永不改变。因此,林克去到阿卡来研究所寻求帮助,他得到新的道具——变形棋盘。

这个变形棋盘可以根据输入的两个参数的(p,q)创造全新的棋盘空间。

如下图分别是(p,q)为(3,9) , (6,3) ,以及(5,5)的棋盘空间。

请问对于每一种棋盘(p,q),2D骑士是否有一种一次遍历所有棋盘方格的路线?

如果有,请输出这条路线(若有多条路线,请输出字典序最小的路线)。

如果没有,请输出无。

输入

输入数据第一行为正整数n,代表有多少组输入样例

接下来n行是两个整数代表行p和列q, 代表变形棋盘的行列参数,其中(1 <= p * q <= 26)。

样例

5
5 1
5 2
5 3
5 4
5 5

输出

每个样例的输出2行,格式如下:

"#i:" 其中i代表第i种棋盘

骑士跳过的每个格子(每个访问的格子用大写字母加数字表示),一条可行的路径输出如(A1B3C1A2B4C2A3B1C3A4B2C4),

如果没有可行方案,则第二行输出:none

样例

#1:
none
#2:
none
#3:
none
#4:
A1B3A5C4D2B1A3B5D4C2B4A2C1D3C5A4B2D1C3D5
#5:
A1B3A5C4A3B1D2E4C5A4B2D1C3B5D4E2C1A2B4D5E3C2E1D3E5

思路

我们很容易看出来可以用深度优先搜索来解决这个问题。我们先声明一个足够大的二维数组作为棋盘,然后遍历每个格子作为起点,利用方向向量进行深度优先搜索,如果找到了一条路径,我们就把它存到答案中,并结束搜索。如果遍历了所有格子作为起点搜索后仍然没有找到一条路径,则说明无解,输出none。

注意事项

  1. 方向向量的遍历顺序一定要和题目所给的顺序一致。
  2. 解答每个样例之前,都要清空答案。
  3. 在找到一条路径后不能继续递归,否则会导致超时。
  4. 注意对应二维数组的行列和棋盘的行列。

代码实现

深搜函数和一些全局变量。

#include<iostream>
#include<vector>
using namespace std;
int dx[8] = { -2,-2,-1,-1,1,1,2,2 };//方向向量,注意行列,且顺序一定要和题目一致
int dy[8] = { -1,1,-2,2,-2,2,-1,1 };
int che[27][27];//声明全局二维数组作为棋盘
int r, c;
int flag = 1;
vector<pair<int, int>> path;
vector<pair<int, int>> res;
bool check() {//检查棋盘上是否每个格子都被走过
	for (int i = 1; i <= r; i++) {
		for (int j = 1; j <= c; j++)
			if (che[i][j] != 1)
				return false;//如果有格子没被走过,返回false
	}
	return true;//否则,返回true
}
void dfs(int x,int y) {//深搜函数
	che[y][x] = 1;//把起点标记为1,表示已走过
	path.push_back({ x,y });
	if (check()&&flag)//如果是第一次全部走完棋盘,则把本次路径放入答案中
	{
		flag = 0;//把flag标记为0,后续不再回溯搜索了
		res.operator=(path);
		return;
	}
	for (int i = 0; i < 8; i++) {//如果棋盘还没走完,就继续走
		int nx = x + dx[i];//注意走格子的顺序一定要和题目给的顺序一致
		int ny = y + dy[i];
		if (nx >= 1 && nx <= c && ny >= 1 && ny <= r&&che[ny][nx]!=1) {
			//如果找到一个合法且没有走过的格子
			if (flag)//如果还没找到过答案
				dfs(nx, ny);//递归继续向深处搜索
			else
				break;//否则,直接退出循环
		}
	}
	che[y][x] = 0;//回溯,探索另一种走法
	path.pop_back();
}

加上主函数,问题解决。

int main() {
	int n;
	cin >> n;//n个测试样例
	for (int i = 0; i < n; i++) {
		flag = 1;
		res.clear();//搜索之前先清空答案
		cin >> r >> c;
		for (int j = 1; j <= r; j++) {
			for (int k = 1; k <= c; k++)
			{
				//遍历棋盘的每个格子,分别作为起点
				path.clear();//搜索之前,清空路径
				dfs(k, j);//开始搜索
			}
		}
		cout << "#" << i + 1 <<":"<< endl;
		if (res.empty()) {//如果没找到解输出none
			cout << "none" << endl;
		}
		else{//否则输出路径
			for (auto it = res.begin(); it != res.end(); it++) {
				printf("%c%d", it->first + 'A' - 1, it->second);
			}
			cout << endl;
		}
	}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值