0
点赞
收藏
分享

微信扫一扫

蓝桥杯算法入门_06 (DFS)

悬灸人雪洋 2022-03-11 阅读 80
#include <iostream>
using namespace std;

/*深度优先搜索  dfs算法

"一条路走到黑"
可以用递归实现

搜索树、迷宫


*/

/*实现迷宫
迷宫朴素解法:每一步尝试所有方向 dfs下一步+标记

//S入口 T出口   .可走  , *障碍

样例输入:
5 6
....S*
.***..
.*..*.
*.***.
.T....


输出:
....m*
.***mm
.*..*m
*.***m
.Tmmmm
9

测试最短更新
样例输入:
5 6
....S*
.**...
.*..*.
*..**.
.T....

输出:
...mm*
.**m..
.*mm*.
*mm**.
.T....
7

*/
#include<string>
int dir_01[4][2] = {{-1,0},{0,-1},{1,0},{0,1}};  //简化代码  四个方向,每行为 x,y 方向排序逆时针用得多  ,看题
int n_01,m_01;//行 列
string maze_01[110]; //一维存放地图  字符串数组
bool vis_01[110][110]; //地图路线标记
int ans_01 = 1000000000; //给大数,保证能更新答案
bool in_01(int x,int y) { //判断 x,y是否在取值范围内
	return 0 <= x && x < n_01 && 0 <= y && y < m_01;
}
bool dfs_01(int x,int y,int step) { //输入下一步的坐标 判断是否可行    //step记录每种路径的长度,找到最短路径
	if(maze_01[x][y] == 'T') {//到达终点
		if(step < ans_01) { //更新
			ans_01 = step;
		}
		return true;
	}
	vis_01[x][y] = 1; //标记1为走过
	//	if(maze_01[x][y] != 'S'){  } //第二次遍历 退回S时会改 ,或者
	maze_01[x][y] = 'm';//标记S -- T 通路路径

	for(int i = 0; i < 4; i++) {
		int tx = x + dir_01[i][0];
		int ty = y + dir_01[i][1];
		//tx,ty不越界(取值范围内) 不是障碍物 且未走过 ,可以在此步(tx,ty)为基础搜索下一步
		if(in_01(tx,ty) && maze_01[tx][ty] != '*' && !vis_01[tx][ty]) {
			if(dfs_01(tx,ty,step + 1)) {
				return true;
			}
		}
	}
	vis_01[x][y] = 0; //搜所有情况时(找最短)一定要恢复标记
	maze_01[x][y] = '.';//恢复未走的状态
	return false;


	/*复杂版 copy也不慢
	int tx = x - 1,ty = y ; //往左走   要遵循顺时针或逆时针方向判断!!!!!
	if(in_01(tx,ty) && maze_01[tx][ty] != '*' && !vis_01[tx][ty]) { //不越界 且未走过 (走过还未到终点说明不通)
		if(dfs_01(tx,ty)) {
			return true;
		}
	}
	tx = x ,ty = y - 1; //往下走
	if(in_01(tx,ty) && maze_01[tx][ty] != '*' && !vis_01[tx][ty]) { //不越界 且未走过 (走过还未到终点说明不通)
		if(dfs_01(tx,ty)) {
			return true;
		}
	}
	tx = x + 1,ty = y ; //往右走
	if(in_01(tx,ty) && maze_01[tx][ty] != '*' && !vis_01[tx][ty]) { //不越界 且未走过 (走过还未到终点说明不通)
		if(dfs_01(tx,ty)) {
			return true;
		}
	}
	tx = x ,ty = y + 1; //往上走
	if(in_01(tx,ty) && maze_01[tx][ty] != '*' && !vis_01[tx][ty]) { //不越界 且未走过 (走过还未到终点说明不通)
		if(dfs_01(tx,ty)) {
			return true;
		}
	}
	vis_01[x][y] = 0; //恢复标记 ,找全部解
	maze_01[x][y] = '.';//恢复未走的状态
	return false;
	*/
}

void test_01() {
	//输入迷宫地图
	cin >> n_01 >> m_01;
	for(int i = 0; i < n_01; i++) {
		cin >> maze_01[i]; //每个位置存一行 m
	}
	int x, y,step;
	for(int i = 0; i < n_01; i++) {
		for(int j = 0; j < m_01; j++) {
			if(maze_01[i][j] == 'S') {
				x = i,y = j;//设立起始位置
			}
		}
	}
	if(dfs_01(x,y,0)) {  //别忘了调用!
		for(int i = 0; i < n_01; i++) {  //有bug时先打印 测试
			cout<< maze_01[i] << endl;
		}
		cout<< ans_01  <<endl;  //输出最短路径长度   ans设置全局!  ,此处没有把T终点变为m ,但是起点S 变成m,等效
	} else {
		cout<< "NO!" << endl;
	}

	return;
}

/*象棋走马
日字型
不超出棋盘 , 不走到有棋子处


S起点   T终点   #障碍  .通路
马走日字型能否 S --> T

样例输入:
.#....#S#
..#.#.#..
..##.#..#
......##.
...T.....
...#.#...
...#.....
...##....
.........
.##......


输出:
Yes



*/




#include<cstdio>
char s_02[10][10];
bool f_02;
int dir_02[8][2] =  {{2,1},{1,2},{-1,2},{-2,1},{-2,-1},{-1,-2},{1,-2},{2,-1}};  //表示马能走的八个方向
bool vis_02[10][10];
bool in_02(int x,int y) { //判断 x,y是否在取值范围内
	return 0 <= x && x < 10 && 0 <= y && y < 9;
}
void dfs_02(int x,int y) {
	vis_02[x][y] = true;  //访问时标记 true
	//测试s_02[x][y] =='m';   其他遍历完加return   且有做修改,不通均无return,最后要恢复 vis_02[x][y] = false;   	s_02[x][y] =='.';
	if(f_02) {
		return;  //找到就结束 , 减少时间复杂度 !!
	}
	if(s_02[x][y] == 'T') {  //找到出口
		f_02 = true;
		return;
	}
	for(int i = 0; i < 8; i++) { //遍历方向
		int tx = x + dir_02[i][0];
		int ty = y + dir_02[i][1];
		if(in_02(tx,ty) && s_02[tx][ty] != '#' && !vis_02[tx][ty] ) { //不越界且未访问的情况下 判断下一步
			dfs_02(tx,ty);
		}
	}

}


void test_02() {
	int x,y;
	for(int i = 0; i < 10; i++) {
		scanf("%s",s_02[i]);
	}
	for(int i = 0; i < 10; i++) { //棋盘一半大小 10 * 9
		for(int j = 0; j < 9; j++) {
			if(s_02[i][j] == 'S') { //设立起始点
				x = i;
				y = j;
			}
		}
	}
	dfs_02(x,y);//别忘了!
	/*测试
	for(int i = 0; i < 10; i++) {
		cout<<s_02[i] <<endl;
	}
	*/
	if(f_02) {
		printf("Yes\n");
	} else {
		printf("No\n");
	}
}

/*搜索救援
.代表空地  ,  #代表草丛    ###连在一块的是一片草丛 ,所有格子之间都联通
每个草地需要派一个人去寻找 ,同一块草地的两个人可以相互看见,空地的人看不见草丛的人。
算出至少需要多少人救援 (求有几片草丛)

输入n m   行,列 ∈[1,100]
输入地图

样例输入:
5 6
.#....
..#...
..#..#
...##.
.#....

输出:
5

*/

#include<cstdio>
char mp_03[105][105];
bool vis_03[105][105];
int n_03,m_03;
void dfs_03(int x,int y) {
	if(x < 0 || x >= n_03 || y < 0 || y >= m_03 || vis_03[x][y] || mp_03[x][y]== '.') { //超出边界或走到空地,遇到同一块草丛就连续不退出
		return;
	}
	vis_03[x][y] = true; //走过标记为true
	dfs_03(x - 1,y);
	dfs_03(x,y - 1);
	dfs_03(x + 1,y);
	dfs_03(x,y + 1);
}

void test_03() {
	int cnt = 0;
	scanf("%d%d",&n_03,&m_03);
	for(int i = 0; i < n_03; i++) {
		scanf("%s",mp_03[i]);
	}
	for(int i = 0; i < n_03; i++) {
		for(int j = 0; j < m_03; j++) {
			if(!vis_03[i][j] && mp_03[i][j] == '#') {
				dfs_03(i,j);
				cnt++;
			}
		}
	}
	printf("%d\n",cnt);
	return;
}

/*

样例输入:
5 5
s####
.####
.####
.####
....e


输出:
1


*/


int n_04,m_04,x_04,y_04,ans_04;  //x,y表示行列下标
char mp_04[15][15];
bool vis_04[15][15];
void dfs_04(int x,int y) { //参数x !=  x_04 调试半天...
	//此步坐标 超出边界或已经走过 或是障碍物 返回
	if(x < 0 || x >= n_04 || y < 0 || y >= m_04 || vis_04[x][y] || mp_04[x][y]== '#') {
		return;
	}
	if(mp_04[x][y] == 'e') { //到达终点
		ans_04++;  //统计通路数量
		return;
	}
	vis_04[x][y] = true; //走过标记为true
	//mp_04[x][y]= 'm';
	dfs_04(x - 1,y);
	dfs_04(x + 1,y);
	dfs_04(x,y - 1);
	dfs_04(x,y + 1);
	vis_04[x][y] = false; //找所有路径 ,一定要情空标记
}

void test_04() {
	scanf("%d%d",&n_04,&m_04);
	for(int i = 0; i < n_04; i++) {
		scanf("%s",mp_04[i]);//输入地图 一行占一位
	}
	for(int i = 0; i < n_04; i++) {
		for(int j = 0; j < m_04; j++) {
			if(mp_04[i][j] == 's') { //设置起点
				x_04 = i;
				y_04 = j;
			}
		}
	}
	dfs_04(x_04,y_04);
	/*测试 地图  可标记走过处 元素m 
	for(int i = 0; i < n_04; i++) {
		printf("%s\n",mp_04[i]);
	}
	*/
	printf("%d\n",ans_04);
	return;
}

/*求最大连续草丛(其余与test_03一致) 

样例输入:
5 6
.#....
..#...
..#..#
...##.
.#....

输出:
2


*/

int n_05,m_05,cnt_05,ans_05;
char mp_05[1005][1005];
bool vis_05[1005][1005];
void dfs_05(int x,int y) {
	//此步坐标 超出边界或已经走过 或不是草丛 返回
	if(x < 0 || x >= n_05 || y < 0 || y >= m_05 || vis_05[x][y] || mp_05[x][y]== '.') {
		return;
	}
	vis[x][y] = true; //走过标记为true
	cnt_05++; //记录草丛大小
	dfs_05(x - 1,y);
	dfs_05(x,y - 1);
	dfs_05(x + 1,y);
	dfs_05(x,y + 1); //遍历一遍即可 ,不用清空标记 
}

void test_05() { //先写主 再 完成dfs_05
	scanf("%d%d",&n_05,&m_05);
	for(int i = 0; i < n_05; i++) {
		scanf("%s",mp_05[i]);//输入地图 一行占一位
	}
	for(int i = 0; i < n_05; i++) {
		for(int j = 0; j < m_05; j++) {
			if( !vis_05[i][j] && mp_05[i][j] == '#') {  //此步未访问过,且不是障碍物 
				cnt_05 = 0;
				dfs_05(i,j); //搜索草丛 
				if(ans_05 < cnt_05) { //找最大,更新 
					ans_05 = cnt_05;
				}
			}
		}
	}
	printf("%d\n",ans_05); //最大连续草丛 
	return;
}


int main() {
	test_05();
	return 0;
}







迷宫1 --test_01

 

举报

相关推荐

0 条评论