有关dfs、bfs解决迷宫问题的个人见解
可以使用BFS或者DFS方法解决的迷宫问题!
题目如下:
kotori在一个n*m迷宫里,迷宫的最外层被岩浆淹没,无法涉足,迷宫内有k个出口。kotori只能上下左右四个方向移动。她想知道有多少出口是她能到达的,最近的出口离她有多远?
输入描述:
第一行为两个整数n和m,代表迷宫的行和列数 (1≤n,m≤30) 后面紧跟着n行长度为m的字符串来描述迷宫。'k'代表kotori开始的位置,'.'代表道路,'*'代表墙壁,'e'代表出口。保证输入合法。
输出描述:
若有出口可以抵达,则输出2个整数,第一个代表kotori可选择的出口的数量,第二个代表kotori到最近的出口的步数。(注意,kotori到达出口一定会离开迷宫) 若没有出口可以抵达,则输出-1。
#include<iostream>
#include<string.h>
using namespace std;
char map[][];
int use[][];
int dir[][] = {{,},{,},{,-},{-,}}; //上下左右四个方向
int minn = ; int pan(int x,int y)
{
if( <= x && x <= && <= y && y <= && (map[x][y] == '.' || map[x][y]=='k')) return ;
else return ;
} void dfs(int x,int y,int step)
{
// 递归程序,必须要设置整个程序的出口,在dfs中,即当走到迷宫出口处即可结束程序
if(map[x][y] == 'e')
{
cout<<"success"<<endl;
if(step < minn) minn = step;
return;
}
for(int i = ; i < ; i++)
{
if(pan(x,y) && use[x][y] != )
{
use[x][y] = ;
cout<<"dd";
cout<<" "<<map[x+dir[i][]][y+dir[i][]]<<endl;
dfs(x+dir[i][],y+dir[i][],step+);
use[x][y] = ;
}
} }
int main()
{
int n;
int m;
cin >> n >> m;
// 4,5行已经定义了map和use数据,所以在此处不必int map[n][m],直接map[n][m]即可,否则报错
map[n][m];
use[n][m];
memset(use,,sizeof(use));
int x_start = ;
int y_start = ;
int step = ;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cin >> map[i][j];
if(map[i][j] == 'k')
{
x_start = i;
y_start = j;
}
}
}
cout<<x_start<<" "<<y_start<<endl;
dfs(x_start, y_start, step);
cout<<"最小步数"<<minn<<endl;
}

BFS解决如下:
(1)自己写的有缺陷的代码:
#include<iostream>
#include<queue>
#include<string.h>
using namespace std;
char map[][];
int vis[][];
int use[][];
int m,n;
int x_start,y_start;
queue<int> que;
int dir[][] = {{,},{,-},{,},{-,}};
int cnt = ;
int mi = ; int pan(int x,int y)
{
if( <= x && x <= n- && <= y && y <= m - &&map[x][y] != '*') return ;
else return ;
} void bfs(int x,int y)
{
int x1 = x;
int y1 = y;
while(!que.empty())
{
vis[x1][y1] = ;
x1 = que.front();
que.pop();
y1 = que.front();
que.pop();
cout<<"x1:"<<x1<<" "<<"y1:"<<y1<<endl;
if(map[x1][y1] == 'e')
{
if(use[x1][y1] == )
{
cnt++;
use[x1][y1]=;
}
continue;
} for(int i = ; i < ; i++)
{
int xx = x1 + dir[i][];
int yy = y1 + dir[i][];
if(pan(xx,yy) && vis[xx][yy] == )
{
cout<<"dd"<<endl;
cout<<xx<<" "<<yy<<endl;
que.push(xx);
que.push(yy);
vis[xx][yy] = ;
}
}
}
} int main()
{
memset(vis,,sizeof(vis));
memset(use,,sizeof(use));
cin >> n >> m;
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cin >> map[i][j];
if(map[i][j] == 'k')
{
x_start = i;
y_start = j;
}
}
}
que.push(x_start);
que.push(y_start);
bfs(x_start,y_start);
cout<<cnt<<endl; }
对于每个点每个状态我采用的是直接利用队列记录他们的坐标值,而不是如AC代码一样利用结构体记录每个点的每个状态。所以导致我整个程序还是存在很大的缺陷,例如求最短路径的时候就比较困难。
所以对于BFS的题目,强烈建议把每个点每个状态先用结构体表示,然后利用队列记录这些结构体即可。
(2)AC代码
#include<bits/stdc++.h>
using namespace std;
char a[][];
bool usd[][];
int Move[][]={{,},{,},{-,},{,-}};
struct now
{
int x,y,dis;
};
queue<now>q;
int main()
{
int n,m,cnt=;
scanf("%d%d",&n,&m);
now s;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
cin>>a[i][j];
if(a[i][j]=='k')
{
s.x=i;
s.y=j;
s.dis=;
}
}
q.push(s);
int ans=;
while(!q.empty())
{
now Now=q.front();
q.pop();
if(a[Now.x][Now.y]=='e')
{
if(!usd[Now.x][Now.y])
{
++cnt;
ans=min(ans,Now.dis);
}
usd[Now.x][Now.y]=true;
continue; //到达出口"e"处就必须跳过一下步骤,不能在对出口点“e”进行下面的扩展步骤(上下左右)
}
usd[Now.x][Now.y]=true;
for(int i=;i<;++i)
{
int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
{
now t;
t.x=xx;
t.y=yy;
t.dis=d+;
q.push(t);
}
}
}
if(!cnt)
return !printf("-1\n");
printf("%d %d\n",cnt,ans);
return ;
}

带路径输出的BFS(路径的输出主要依靠递归程序,记录每个点的结构体还需要记录每个点的前驱节点的坐标)
#include<bits/stdc++.h>
using namespace std;
char a[][];
bool usd[][];
int Move[][]={{,},{,},{-,},{,-}};
struct now
{
int x,y,dis,pre_x,pre_y;
};
queue<now>q;
now buf[];
int count1 = ; void print(int x,int y)
{
int temp;
for(int i = ; i < count1; i++)
{
if(buf[i].x == x && buf[i].y == y) temp = i;
}
if(x == - && y == -) return;
else
{
print(buf[temp].pre_x,buf[temp].pre_y);
cout<<"("<<x<<","<<y<<")"<<endl;
}
} int main()
{
int n,m,cnt=;
scanf("%d%d",&n,&m);
now s;
for(int i=;i<=n;++i)
for(int j=;j<=m;++j)
{
cin>>a[i][j];
if(a[i][j]=='k')
{
s.x=i;
s.y=j;
s.pre_x = -;
s.pre_y = -;
s.dis=;
}
}
q.push(s);
int ans=;
while(!q.empty())
{
now Now=q.front();
buf[count1++] = Now;
q.pop();
if(a[Now.x][Now.y]=='e')
{
if(!usd[Now.x][Now.y])
{
++cnt;
ans=min(ans,Now.dis);
usd[Now.x][Now.y]=true;
print(Now.x,Now.y);
}
continue;
}
usd[Now.x][Now.y]=true;
for(int i=;i<;++i)
{
int xx=Now.x+Move[i][],yy=Now.y+Move[i][],d=Now.dis;
if(xx<=n&&xx>=&&yy>=&&yy<=m&&!usd[xx][yy]&&a[xx][yy]!='*')
{
now t;
t.x=xx;
t.y=yy;
t.pre_x = Now.x;
t.pre_y = Now.y;
t.dis=d+;
q.push(t);
}
}
}
if(!cnt)
return !printf("-1\n");
printf("%d %d\n",cnt,ans);
// for(int i = 0; i < count1; i++)
// {
// cout<<buf[i].x<<" "<<buf[i].y<<" "<<buf[i].pre_x<<" "<<buf[i].pre_y<<endl;
// }
return ;
}
利用dfs解决最大连通块问题!
题目描述
农场主约翰的农场在最近的一场风暴中被洪水淹没,这一事实只因他的奶牛极度害怕水的消息而恶化。
然而,他的保险公司只会根据他农场最大的“湖”的大小来偿还他一笔钱。
农场表示为一个矩形网格,有N(1≤N≤100)行和M(1≤M≤100)列。网格中的每个格子要么是干的,
要么是被淹没的,而恰好有K(1≤K≤N×M)个格子是被淹没的。正如人们所期望的,一个“湖”有一个
中心格子,其他格子通过共享一条边(只有四个方向,对角线不算的意思)与之相连。任何与中央格子共享一条边或与中央格
输入描述:
第一行有三个整数N,M,K,分别表示这个矩形网格有N行,M列,K个被淹没的格子。 接下来K行,每一行有两个整数R,C。表示被淹没的格子在第R行,第C列。
输出描述:
输出最大的“湖”所包含的格子数目
输入
3 4 5
3 2
2 2
3 1
2 3
1 1
输出
4
#include<iostream>
using namespace std;
int map[][];
int vis[][] = {};
int used[][] = {};
int dir[][] = {{,},{-,},{,},{,-}};
int n,m,k;
int cnt = ;
int maxx = -;
int pan(int x,int y)
{
if(map[x][y] == && <= x && x <= n- && y <= m- && y >= && vis[x][y] == && used[x][y]==)
{
return ;
}
else return ;
} void dfs(int x,int y,int c) //连通块问题就不像迷宫问题有递归出口!!!!
{
vis[x][y] = ;
// cout<<x<<" "<<y<<" dd"<<endl;
for(int i = ; i < ; i++)
{
int xx = x + dir[i][];
int yy = y + dir[i][];
if(pan(xx,yy))
{
// cout<<xx<<" "<<yy<<endl;
vis[xx][yy] = ;
used[xx][yy] = ; // used数组是防止多次记录连通块!
cnt++;
c = cnt; // 这一块必须注意,不能直接传入cnt,因为递归函数是放在栈中,倘若传入cnt,递归函数出栈时,cnt的值也会变化,所以用c代替cnt.
dfs(xx,yy,c);
vis[xx][yy] = ;
}
}
} int main()
{
cin >> n >> m >> k;
map[n][m];
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++) map[i][j] = ;
}
for(int i = ; i < k; i++)
{
int x,y;
cin >> x >> y;
map[x-][y-] = ;
}
// for(int i = 0; i < n; i++) 打印整个地图
// {
// for(int j = 0; j < m; j++)
// {
// cout<<map[i][j];
// }
// cout<<endl;
// }
for(int i = ; i < n; i++)
{
for(int j = ; j < m; j++)
{
cnt = ;
if(map[i][j] == )
{
dfs(i,j,cnt);
if(cnt > maxx) maxx = cnt;
}
}
}
cout<<maxx<<endl; }
本题总结:
1.利用dfs解决连通块问题与利用dfs解决迷宫问题存在一定的区别:
(1)迷宫问题有固定的入口或者出口,而连通块问题就没有所谓的出口或者入口,它需要遍历map[][]数组中的每个元素!
有关dfs、bfs解决迷宫问题的个人见解的更多相关文章
- 用BFS解决迷宫问题
在一个n*n的矩阵里走,从原点(0,0)開始走到终点(n-1,n-1),仅仅能上下左右4个方向走.仅仅能在给定的矩阵里走,求最短步数. n*n是01矩阵,0代表该格子没有障碍.为1表示有障碍物. in ...
- 【DFS/BFS】NYOJ-58-最少步数(迷宫最短路径问题)
[题目链接:NYOJ-58] 经典的搜索问题,想必这题用广搜的会比较多,所以我首先使的也是广搜,但其实深搜同样也是可以的. 不考虑剪枝的话,两种方法实践消耗相同,但是深搜相比广搜内存低一点. 我想,因 ...
- [LeetCode] BFS解决的题目
一.130 Surrounded Regions(https://leetcode.com/problems/surrounded-regions/description/) 题目: 解法: 这道题 ...
- POJ 3083 -- Children of the Candy Corn(DFS+BFS)TLE
POJ 3083 -- Children of the Candy Corn(DFS+BFS) 题意: 给定一个迷宫,S是起点,E是终点,#是墙不可走,.可以走 1)先输出左转优先时,从S到E的步数 ...
- DFS/BFS+思维 HDOJ 5325 Crazy Bobo
题目传送门 /* 题意:给一个树,节点上有权值,问最多能找出多少个点满足在树上是连通的并且按照权值排序后相邻的点 在树上的路径权值都小于这两个点 DFS/BFS+思维:按照权值的大小,从小的到大的连有 ...
- ID(dfs+bfs)-hdu-4127-Flood-it!
题目链接: http://acm.hdu.edu.cn/showproblem.php?pid=4127 题目意思: 给n*n的方格,每个格子有一种颜色(0~5),每次可以选择一种颜色,使得和左上角相 ...
- [LeetCode] 130. Surrounded Regions_Medium tag: DFS/BFS
Given a 2D board containing 'X' and 'O' (the letter O), capture all regions surrounded by 'X'. A reg ...
- HDU 4771 (DFS+BFS)
Problem Description Harry Potter has some precious. For example, his invisible robe, his wand and hi ...
- DFS/BFS视频讲解
视频链接:https://www.bilibili.com/video/av12019553?share_medium=android&share_source=qq&bbid=XZ7 ...
随机推荐
- QQ互联登陆(Java)
一.准备部分 1.账户注册 腾讯开放平台网址: https://connect.qq.com/index.html 首先需要到开放平台注册QQ互联开发者身份.注册之后创建一个网站应用,注意,需要备案成 ...
- Good Article Good sentence HDU - 4416 (后缀数组)
Good Article Good sentence \[ Time Limit: 3000 ms\quad Memory Limit: 32768 kB \] 题意 给出一个 \(S\) 串,在给出 ...
- svn服务器命令(转)
*验证svn安装是否成功 #svnadmin --version *创建svn的数据仓库 #svnadmin create /data/svn/svndata/spms *启动svn服务 #svnse ...
- [Android] Android studio gradle 插件的版本号和 gradle 的版本号 的对应关系
[Android] Android studio gradle 插件的版本号和 gradle 的版本号 的对应关系 本博客地址: wukong1688 本文原文地址:https://www.cnblo ...
- maven的安装、路径配置、修改库文件路径和eclipse中的配置、创建maven工程。
注:本文来源于:杨四郎2018 <maven的安装.路径配置.修改库文件路径和eclipse中的配置.创建maven工程> 一.maven的安装 首先,先到官网去下载maven.这里是官 ...
- Java实现PV操作 | 生产者与消费者
导语 在学习操作系统的过程中,PV操作是很重要的一个环节.然而面对书本上枯燥的代码,每一个爱好技术的人总是想能亲自去实现.现在我要推出一个专题,专门讲述如何用Java实现PV操作,让操作系统背后的逻辑 ...
- shell 脚本接收参数
test.sh #!/bin/bash echo "脚本名$0" echo "第1个参数$1" echo "第2个参数$2" echo &q ...
- 如何在ProXmoX VE 下虚拟机安装 黑群晖 DSM 6.1.6
ProXmoX 官方下载地址: https://www.proxmox.com/en/downloads Proxmox是一个非常优秀的开源虚拟化环境,集诸多优点于一身:开源免费,稳定可靠,架构简洁, ...
- js转义问题
js转义问题有很多场景,比如常见的根据某个字符串删除或者修改以及将某字符串传递至某个页面. 今天以一个简单的示例代码为例: <html> <head> <meta htt ...
- 数据接口-免费版(股票数据API)
获取股票数据的源头主要有:数据超市.雅虎.新浪.Google.和讯.搜狐.ChinaStockWebService.东方财富客户端.证券之星.网易财经. 数据超市 2016年5月6日更新.根据最近频繁 ...