深度优先搜索DFS回溯与路径打印(1431. 迷宫的第一条出路、1360. 卒的遍历、1362. 马的遍历、1739. 迷宫的所有路径、1411. 迷宫的路径)

 题单地址:题单中心-东方博宜OJ

1431. 迷宫的第一条出路

问题描述

已知一 N×N 的迷宫,允许往上、下、左、右四个方向行走,现请你按照左、上、右、下顺序进行搜索,找出第一条从左上角到右下角的路径。

输入

输入数据有若干行,第一行有一个自然数 N(N ≤ 20),表示迷宫的大小;

其后有 N 行数据,每行有 N 个 0 或 1(数字之间没有空格,0 表示可以通过,1 表示不能通过),用以描述迷宫地图。入口在左上角 (1,1)处,出口在右下角(N,N) 处。

所有迷宫保证存在从入口到出口的可行路径。

输出

输出数据仅一行,为按照要求的搜索顺序找到的从入口到出口的第一条路径(搜索顺序:左、上、右、下)。

样例

输入

4

0001

0100

0010

0110

输出

(1,1)->(1,2)->(1,3)->(2,3)->(2,4)->(3,4)->(4,4)

解析:dfs参数包括当前位置和当前步数,使用一个vis数组记录走过的位置,到终点后退出搜索输出vis数组即可。

#include <bits/stdc++.h>
using namespace std;

int n, sum, vis[1005][2], f = 0;
int a[155][155];
int dir[4][2] = {{0, -1}, {-1, 0}, {0, 1}, {1, 0}};

void dfs(int x, int y, int len){
	vis[len][0] = x, vis[len][1] = y;
	a[x][y] = 1;
	if(x == n && y == n){
		f = 1;
		sum = len;
		return ;
	}
	for(int i = 0; i < 4; i++){
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if(xx >= 1 && yy >= 1 && xx <= n && yy <= n && a[xx][yy] == 0 && f == 0)
			dfs(xx, yy, len + 1);
	}
}

int main(){
	cin >> n;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= n; j++){
			char c;
			cin >> c;
			a[i][j] = c - '0';
		}
	}
	dfs(1, 1, 1);
	for(int i = 1; i <= sum; i++){
		printf("(%d,%d)", vis[i][0], vis[i][1]);
		if(i != sum)cout << "->";
	}
    return 0;
}

1360. 卒的遍历

问题描述

在一张 n×m 的棋盘上(如 6 行 7 列)的最左上角 (1,1) 的位置有一个卒。该卒只能向下或者向右走,且卒采取的策略是先向下下边走到头就向右,请问从 (1,1) 点走到 (n,m) 点可以怎样走,输出这些走法。

输入

两个整数 n,m 代表棋盘大小(3 ≤ n ≤ 8, 3 ≤ m ≤ 8)

输出

卒的行走路线。

样例

输入

3 3

输出

1:1,1->2,1->3,1->3,2->3,3

2:1,1->2,1->2,2->3,2->3,3

3:1,1->2,1->2,2->2,3->3,3

4:1,1->1,2->2,2->3,2->3,3

5:1,1->1,2->2,2->2,3->3,3

6:1,1->1,2->1,3->2,3->3,3

解析:dfs参数包括当前位置和当前步数,使用一个vis数组记录走过的位置,并标记该点走过,到终点后输出vis数组即可。

#include <bits/stdc++.h>
using namespace std;

int n, m, vis[10005][2], k;
int a[155][155];
int dir[4][2] = {{1, 0}, {0, 1}, {0, -1}, {-1, 0}};

void dfs(int x, int y, int len){
	vis[len][0] = x, vis[len][1] = y;
	if(x == n && y == m){
		k++;
		cout << k << ":";
		for(int i = 1; i <= len; i++){
			printf("%d,%d", vis[i][0], vis[i][1]);
			if(i != len)cout << "->";
			else cout << endl;
		}
	}
	for(int i = 0; i < 2; i++){
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if(xx >= 1 && yy >= 1 && xx <= n && yy <= m && a[xx][yy] == 0){
			a[xx][yy] = 1;
			dfs(xx, yy, len + 1);
			a[xx][yy] = 0;
		}
	}
}

int main(){
	cin >> n >> m;
	dfs(1, 1, 1);
}

1362. 马的遍历

问题描述

中国象棋半张棋盘如图(a)所示。马自左下角往右上角跳。

今规定只许往右跳,不许往左跳,且要求马跳的方式按照(b)图顺时针深度优先递归。比如图(a)中所示为一种跳行路线。如果马要从 0,0 点,跳到 4,8 点,前 6 种跳法的打印格式如下,请参考前 6 种跳的方式,输出马从 0,0 点到 4,8 点所有可能的跳的路线。

1:0,0->2,1->4,2->3,4->4,6->2,7->4,8
2:0,0->2,1->4,2->3,4->1,5->3,6->4,8
3:0,0->2,1->4,2->3,4->1,5->2,7->4,8
4:0,0->2,1->4,2->2,3->4,4->3,6->4,8
5:0,0->2,1->4,2->2,3->4,4->2,5->4,6->2,7->4,8
6:0,0->2,1->4,2->2,3->4,4->2,5->0,6->2,7->4,8

输入

输出

1:0,0->2,1->4,2->3,4->4,6->2,7->4,8
2:0,0->2,1->4,2->3,4->1,5->3,6->4,8
3:0,0->2,1->4,2->3,4->1,5->2,7->4,8
4:0,0->2,1->4,2->2,3->4,4->3,6->4,8
5:0,0->2,1->4,2->2,3->4,4->2,5->4,6->2,7->4,8
6:0,0->2,1->4,2->2,3->4,4->2,5->0,6->2,7->4,8

解析:dfs参数包括当前位置和当前步数,使用一个vis数组记录走过的位置,并标记该点走过,到终点后输出vis数组即可。注意马的前进方向和步数。

#include <bits/stdc++.h>
using namespace std;

int n, m, vis[10005][2], k;
int a[155][155];
int dir[4][2] = {{2, 1}, {1, 2}, {-1, 2}, {-2, 1}};

void dfs(int x, int y, int len){
	vis[len][0] = x, vis[len][1] = y;
	if(x == 4 && y == 8){
		k++;
		cout << k << ":";
		for(int i = 1; i <= len; i++){
			printf("%d,%d", vis[i][0], vis[i][1]);
			if(i != len)cout << "->";
			else cout << endl;
		}
	}
	for(int i = 0; i < 4; i++){
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if(xx >= 0 && yy >= 0 && xx <= 4 && yy <= 8 && a[xx][yy] == 0){
			a[xx][yy] = 1;
			dfs(xx, yy, len + 1);
			a[xx][yy] = 0;
		}
	}
}

int main(){
	dfs(0, 0, 1);
}

1739. 迷宫的所有路径

问题描述

已知一 N×N 的迷宫,允许往上、下、左、右四个方向行走,且迷宫中没有任何障碍,所有的点都可以走。

现请你按照右、下、左、上顺序进行搜索,找出从左上角到右下角的所有路径。

输入

输入一个整数 N(N ≤ 5)代表迷宫的大小。

输出

按右、下、左、上搜索顺序探索迷宫,输出从左上角 (1,1) 点走到右下角 (N,N) 点的所有可能的路径。

样例

输入

3

输出

1:1,1->1,2->1,3->2,3->3,3

2:1,1->1,2->1,3->2,3->2,2->3,2->3,3

3:1,1->1,2->1,3->2,3->2,2->2,1->3,1->3,2->3,3

4:1,1->1,2->2,2->2,3->3,3

5:1,1->1,2->2,2->3,2->3,3

6:1,1->1,2->2,2->2,1->3,1->3,2->3,3

7:1,1->2,1->2,2->2,3->3,3

8:1,1->2,1->2,2->3,2->3,3

9:1,1->2,1->2,2->1,2->1,3->2,3->3,3

10:1,1->2,1->3,1->3,2->3,3

11:1,1->2,1->3,1->3,2->2,2->2,3->3,3

12:1,1->2,1->3,1->3,2->2,2->1,2->1,3->2,3->3,3

解析:dfs参数包括当前位置和当前步数,使用一个vis数组记录走过的位置,并标记该点走过,到终点后输出vis数组即可。注意马的前进方向和步数。

#include <bits/stdc++.h>
using namespace std;

int n, m, vis[10005][2], k;
int a[155][155];
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

void dfs(int x, int y, int len){
	vis[len][0] = x, vis[len][1] = y;
	if(x == n && y == n){
		k++;
		cout << k << ":";
		for(int i = 1; i <= len; i++){
			printf("%d,%d", vis[i][0], vis[i][1]);
			if(i != len)cout << "->";
			else cout << endl;
		}
	}
	for(int i = 0; i < 4; i++){
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if(xx >= 1 && yy >= 1 && xx <= n && yy <= n && a[xx][yy] == 0){
			a[xx][yy] = 1;
			dfs(xx, yy, len + 1);
			a[xx][yy] = 0;
		}
	}
}

int main(){
	cin >> n;
	a[1][1] = 1;
	dfs(1, 1, 1);
}

1411. 迷宫的路径

问题描述

Mitch老鼠在森林里游玩,不小心走进了一个迷宫里面,这个迷宫是一个 n 行 m 列的矩阵,迷宫中有些格子是可以走的,有些格子是不能走的,能走的格子用 o (小写字母 o )表示,不能走的格子用 # 表示。

Mitch选择走出迷宫的策略是:先向右,如果右边走不通则选择向下,如果下边走不通则选择向左,如果左边走不通则选择向上;如果四个方向都走不通,则后退选择其他能走的路径。

Mitch从类似下图所示的迷宫的左上角 (1,1) 点进入迷宫(请注意:入口 1,1 和出口的 n,m 点都不是 # ),请问Mitch有哪些方法可以走出迷宫,走到 (n,m) 点;请编程求出所有可能的路径,输出这些路径,如果不存在任何的路径可以走出迷宫,请输出 no

输入

第一行包含两个整数 n 和 m ,中间用单个空格隔开,代表迷宫的行和列的数量。

接下来 n 行,每行 m 个字符,描述迷宫地图。字符只有o 或 # 两种,o 代表这个格子可以走,# 代表这个格子不能走。( 4 ≤ n, m ≤ 10 )

输出

请按照Mitch选择的走出迷宫的策略,输出所有可能的路径,输出形式请参考样例输出的形式。

如果不存在任何的路径可以走出迷宫,请输出 no

样例

输入

6 5

ooooo

o####

ooooo

#oo#o

oooo#

o#ooo

输出

1:1,1->2,1->3,1->3,2->3,3->4,3->5,3->5,4->6,4->6,5

2:1,1->2,1->3,1->3,2->3,3->4,3->5,3->6,3->6,4->6,5

3:1,1->2,1->3,1->3,2->3,3->4,3->4,2->5,2->5,3->5,4->6,4->6,5

4:1,1->2,1->3,1->3,2->3,3->4,3->4,2->5,2->5,3->6,3->6,4->6,5

5:1,1->2,1->3,1->3,2->4,2->4,3->5,3->5,4->6,4->6,5

6:1,1->2,1->3,1->3,2->4,2->4,3->5,3->6,3->6,4->6,5

7:1,1->2,1->3,1->3,2->4,2->5,2->5,3->5,4->6,4->6,5

8:1,1->2,1->3,1->3,2->4,2->5,2->5,3->6,3->6,4->6,5

解析:dfs参数包括当前位置和当前步数,使用一个vis数组记录走过的位置,并标记该点走过,到终点后输出vis数组即可。

#include <bits/stdc++.h>
using namespace std;

int n, m, vis[100005][2], k;
char a[155][155];
int dir[4][2] = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}};

void dfs(int x, int y, int len){
	vis[len][0] = x, vis[len][1] = y;
	if(x == n && y == m){
		k++;
		cout << k << ":";
		for(int i = 1; i <= len; i++){
			printf("%d,%d", vis[i][0], vis[i][1]);
			if(i != len)cout << "->";
			else cout << endl;
		}
	}
	for(int i = 0; i < 4; i++){
		int xx = x + dir[i][0], yy = y + dir[i][1];
		if(xx >= 1 && yy >= 1 && xx <= n && yy <= n && a[xx][yy] == 'o'){
			a[xx][yy] = '#';
			dfs(xx, yy, len + 1);
			a[xx][yy] = 'o';
		}
	}
}

int main(){
	cin >> n >> m;
	for(int i = 1; i <= n; i++){
		for(int j = 1; j <= m; j++){
			cin >> a[i][j];
		}
	} 
	a[1][1] = '#';
	dfs(1, 1, 1);
	if(k == 0)cout << "no";
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值