本篇文章有一些知识点,需要提前了解,这些原理都能搜到,也很好理解,玛卡不在此赘述了~
①DFS算法是什么,递归可以更好地实现深度优先算法,举例Fibonacci数列,更细分到底层,F(0) F(1)可以看成死胡同,使用栈来实现。
②矩阵类问题 需要用到vector容器、pair工具以及其头文件,内部的函数如push_back等
①迷宫可行路径数(最基本迷宫问题、矩阵移动问题)
题目描述
现有一个n∗m大小的迷宫,其中
1
表示不可通过的墙壁,0
表示平地。每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。求从迷宫左上角到右下角的所有可行路径的条数。
输入描述
第一行两个整数n、m(2≤n≤5,2≤m≤5),分别表示迷宫的行数和列数;
接下来n行,每行m个整数(值为
0
或1
),表示迷宫。输出描述
一个整数,表示可行路径的条数。
样例1
输入
3 3
0 0 0
0 1 0
0 0 0
输出
2
分析
假设左上角坐标是(1,1),行数增加的方向为x增长的方向,列数增加的方向为y增长的方向。
可以得到从左上角到右下角有两条路径:
- (1,1)=>(1,2)=>(1,3)=>(2,3)=>(3,3)
- (1,1)=>(2,1)=>(3,1)=>(3,2)=>(3,3)
初始visited[][]全为True,表示未经过的格子。通过DFS()迭代操作,进行上下右左四种操作,每移动一格进行isValid()判断是否符合标准,符合则将 visited[][]该格子改为False。达到终点则路径数counter加一。
#include <cstdio>
const int MAXN = 5;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int counter = 0;
const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};//指出四种移动方式,上下右左
int dy[MAXD] = {1, -1, 0, 0};
bool isValid(int x, int y) { //判断某点是否超出地图,验证合法性
return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !visited[x][y];
}
void DFS(int x, int y) {
if (x == n - 1 && y == m - 1) { /*到达边界则将路径+1,通过下面的迭代出
来的数据反复进行操作*/
counter++;
return;
}
visited[x][y] = true; //未被走过为True,走过为Flase
for (int i = 0; i < MAXD; i++) { //用dx[]dy[]来实现上下右左移动操作
int nextX = x + dx[i];
int nextY = y + dy[i];
if (isValid(nextX, nextY)) { /*移动后的位置若合法且可通过,则继续进行移动操作
通过迭代实现*/
DFS(nextX, nextY);
}
}
visited[x][y] = false;
}
int main() {
scanf("%d%d", &n, &m); //先完成输入数据操作
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &maze[i][j]);
}
}
DFS(0, 0); //执行DFS(),即左上端点为起点
printf("%d", counter);
return 0;
}
② 指定步数的迷宫问题
题目描述
现有一个n∗m大小的迷宫,其中
1
表示不可通过的墙壁,0
表示平地。每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。现从迷宫左上角出发,问能否在恰好第k步时到达右下角。
输入描述
第一行三个整数n、m、k(2≤n≤5,2≤m≤5,2≤k≤n∗m),分别表示迷宫的行数、列数、移动的步数;接下来n行,每行m个整数(值为
0
或1
),表示迷宫。输出描述
如果可行,那么输出
Yes
,否则输出No
。输入
3 3 4
0 1 0
0 0 0
0 1 0
输出
Yes
#include <cstdio>
const int MAXN = 5;
int n, m, k, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
bool canReach = false;
const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};
bool isValid(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m && maze[x][y] == 0 && !visited[x][y];
}
void DFS(int x, int y, int step) {
if (canReach) { //这一步可以不写
return;
}
if (x == n - 1 && y == m - 1) {
if (step == k) {
canReach = true; //通过设置canReach来记录是否为规定步数
}
return;
}
visited[x][y] = true;
for (int i = 0; i < MAXD; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (step < k && isValid(nextX, nextY)) {
DFS(nextX, nextY, step + 1);
}
}
visited[x][y] = false;
}
int main() {
scanf("%d%d%d", &n, &m, &k);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &maze[i][j]);
}
}
DFS(0, 0, 0);
printf(canReach ? "Yes" : "No");
return 0;
}
③矩阵最大权值问题
题目描述
现有一个n∗m大小的矩阵,矩阵中的每个元素表示该位置的权值。现需要从矩阵左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置)。求最后到达右下角时路径上所有位置的权值之和的最大值。
输入描述
第一行两个整数n、m(2≤n≤5,2≤m≤5),分别表示矩阵的行数和列数;
接下来n行,每行m个整数(−100≤整数≤100),表示矩阵每个位置的权值。
输出描述
一个整数,表示权值之和的最大值。
输入
2 2
1 2
3 4
输出
8
#include <cstdio>
const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;
const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};
bool isValid(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m && !visited[x][y];
}
void DFS(int x, int y, int nowValue) {
if (x == n - 1 && y == m - 1) {
if (nowValue > maxValue) { //需要什么判定值,就在此处设置条件
maxValue = nowValue;
}
return;
}
visited[x][y] = true;
for (int i = 0; i < MAXD; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (isValid(nextX, nextY)) {
int nextValue = nowValue + maze[nextX][nextY];
DFS(nextX, nextY, nextValue);
}
}
visited[x][y] = false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &maze[i][j]);
}
}
DFS(0, 0, maze[0][0]); //初始值为第一个位置的值
printf("%d", maxValue);
return 0;
}
④矩阵最大权值的路径
题目描述
现有一个n∗m大小的矩阵,矩阵中的每个元素表示该位置的权值。现需要从矩阵左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置)。假设左上角坐标是(1,1),行数增加的方向为x增长的方向,列数增加的方向为y增长的方向。求最后到达右下角时路径上所有位置的权值之和最大的路径。
输入描述
第一行两个整数n、m(2≤n≤5,2≤m≤5),分别表示矩阵的行数和列数;
接下来n行,每行m个整数(−100≤整数≤100),表示矩阵每个位置的权值。
输出描述
从左上角的坐标开始,输出若干行(每行两个整数,表示一个坐标),直到右下角的坐标。
数据保证权值之和最大的路径存在且唯一。
输入
2 2
1 2
3 4
输出
1 1
2 1
2 2
#include <cstdio>
#include <vector>
#include <utility>
using namespace std;
typedef pair<int, int> Position; //使用pair将某位置的x,y值合为一体,不需要使用struct
const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;
vector<Position> tempPath, optPath; //分为临时位置和最后位置,vector可理解为可变长数组
const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};
bool isValid(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m && !visited[x][y];
}
void DFS(int x, int y, int nowValue) {
if (x == n - 1 && y == m - 1) {
if (nowValue > maxValue) {
maxValue = nowValue;
optPath = tempPath;
}
return;
}
visited[x][y] = true;
for (int i = 0; i < MAXD; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (isValid(nextX, nextY)) {
int nextValue = nowValue + maze[nextX][nextY];
tempPath.push_back(Position(nextX, nextY)); //该点存入临时位置
DFS(nextX, nextY, nextValue); //临时位置被迭代到新的DFS里
tempPath.pop_back(); //将临时位置清空为0,方便存储新位置
}
}
visited[x][y] = false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &maze[i][j]);
}
}
tempPath.push_back(Position(0, 0));
DFS(0, 0, maze[0][0]);
for (int i = 0; i < optPath.size(); i++) {
printf("%d %d\n", optPath[i].first + 1, optPath[i].second + 1);//.first为pair使用方法
}
return 0;
}
⑤迷宫最大权值(此类问题经常出现,迷宫夺宝什么的)
题目描述
现有一个n∗m大小的迷宫,其中
1
表示不可通过的墙壁,0
表示平地。现需要从迷宫左上角出发到达右下角,每次移动只能向上下左右移动一格(不允许移动到曾经经过的位置),且只能移动到平地上。假设迷宫中每个位置都有权值,求最后到达右下角时路径上所有位置的权值之和的最大值。
输入描述
第一行两个整数n、m(2≤n≤5,2≤m≤5),分别表示矩阵的行数和列数;
接下来n行,每行m个整数(值为
0
或1
),表示迷宫。再接下来n行,每行m个整数(−100≤整数≤100),表示迷宫每个位置的权值。
输出描述
一个整数,表示权值之和的最大值。
输入
3 3
0 0 0
0 1 0
0 0 0
1 2 3
4 5 6
7 8 9
输出
29
从左上角到右下角的最大权值之和为1+4+7+8+9=29。
#include <cstdio>
const int MAXN = 5;
const int INF = 0x3f;
int n, m, maze[MAXN][MAXN], isWall[MAXN][MAXN];
bool visited[MAXN][MAXN] = {false};
int maxValue = -INF;
const int MAXD = 4;
int dx[MAXD] = {0, 0, 1, -1};
int dy[MAXD] = {1, -1, 0, 0};
bool isValid(int x, int y) {
return x >= 0 && x < n && y >= 0 && y < m && !isWall[x][y] && !visited[x][y];
}
void DFS(int x, int y, int nowValue) {
if (x == n - 1 && y == m - 1) {
if (nowValue > maxValue) {
maxValue = nowValue;
}
return;
}
visited[x][y] = true;
for (int i = 0; i < MAXD; i++) {
int nextX = x + dx[i];
int nextY = y + dy[i];
if (isValid(nextX, nextY)) {
int nextValue = nowValue + maze[nextX][nextY];
DFS(nextX, nextY, nextValue);
}
}
visited[x][y] = false;
}
int main() {
scanf("%d%d", &n, &m);
for (int i = 0; i < n; i++) {
for (int j = 0; j < m; j++) {
scanf("%d", &isWall[i][j]);
}
}
for (int i = 0; i < n; i++) { //和上面题一样,顶多带一个值
for (int j = 0; j < m; j++) {
scanf("%d", &maze[i][j]);
}
}
DFS(0, 0, maze[0][0]);
printf("%d", maxValue);
return 0;
}