
上篇我们介绍了bfs算法求取最短路径的应用场景和代码实现,本篇将结合具体题目,进一步深化对其的理解运用。
同样是事先的准备工作,int dx[]和int dy[]分别表示方向,根据迷宫大小建立标记数组,step记录总步数。
class Solution {
public:
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int step=0;
bool vis[101][101]={false};//标记数组
int nearestExit(vector<vector<char>>& maze, vector<int>& entrance) {
int m=maze.size(),n=maze[0].size();
queue<pair<int,int>> q;
q.push({entrance[0],entrance[1]});//起点入队列
vis[entrance[0]][entrance[1]]=true;
while(q.size())
{
step++;
int sz=q.size();
for(int i=0;i<sz;i++)
{
auto [a,b]=q.front();
q.pop();
vis[a][b]=true;
//下一层入队列
for(int j=0;j<4;j++)
{
int x=a+dx[j],y=b+dy[j];
//判断是否可以前进
if(x>=0 && x<m && y>=0 && y<n && maze[x][y]=='.' && vis[x][y]==false)
{
//判断是否为出口
if(x==0 || x==m-1 || y==0 || y==n-1)
{
return step;
}
q.push({x,y});
vis[x][y]=true;
}
}
}
}
return -1;
}
};注意:
start基因可能不在基因库内,如果start不在,则直接返回-1即可。
首先我们需要考虑特殊情况:
那么这种情况直接返回-1即可
基因变化与之前迷宫问题的上下左右类似,只不过在这里是A,G,C,T
class Solution {
public:
int minMutation(string startGene, string endGene, vector<string>& bank) {
unordered_set<string> hash(bank.begin(),bank.end());
unordered_set<string> vis;//标记数组
string change="ACGT";//基因变化
int ret=0;//变化次数
//处理特殊情况
if(startGene==endGene)
{
return 0;
}
if(!hash.count(endGene))
{
return -1;
}
queue<string> q;
q.push(startGene);//起始基因入队列
vis.insert(startGene);
while(q.size())
{
ret++;//更新次数
int sz=q.size();
while(sz--)
{
string t=q.front();
q.pop();
for(int i=0;i<8;i++)//8个字符逐个遍历
{
for(int j=0;j<4;j++)
{
string temp=t;//避免污染源字符串
temp[i]=change[j];//字符变换
if(temp==endGene)
{
return ret;
}//判断是否相等
if(hash.count(temp) && !vis.count(temp))
{
q.push(temp);
vis.insert(temp);
}
}
}
}
}
return -1;
}
};与上题基因变化基本同理,只是每次变化由AGCT变为了任意一个字符
与上题基本同理,不再赘述。
class Solution {
public:
int ladderLength(string beginWord, string endWord, vector<string>& wordList) {
unordered_set<string> vis;//标记数组
unordered_set<string> hash(wordList.begin(),wordList.end());
//处理特殊情况
if(!hash.count(endWord))
{
return 0;
}
int ret=1;//返回长度
queue<string> q;
q.push(beginWord);
vis.insert(beginWord);
while(q.size())
{
ret++;//每层长度+1
int sz=q.size();
while(sz--)
{
string t=q.front();
q.pop();
int m=t.size();//该单词长度
for(int i=0;i<m;i++)
{
for(char ch='a';ch<='z';ch++)
{
string temp=t;//避免污染源字符串
temp[i]=ch;
if(temp==endWord)
{
return ret;
}//成功情况
if(temp!=endWord && hash.count(temp) && !vis.count(temp))
{
vis.insert(temp);
q.push(temp);
}
}
}
}
}
return 0;
}
};0 表示障碍,无法触碰 1 表示地面,可以行走 比 1 大的数 表示有树的单元格,可以行走,数值表示树的高度
首先仍然是准备工作,dx[],dy[],标记数组vis。 由于本题要求砍树高度从低到高进行,因此,我们还需要一个数组记录排序后树的下标
class Solution {
public:
int dx[4]={0,0,-1,1};
int dy[4]={1,-1,0,0};
int m,n;//数组规模
int ret=0;//最终步数
bool vis[51][51];//标记数组
int bfs(vector<vector<int>>& forest,int bx,int by,int ex,int ey)
{
queue<pair<int,int>> q;
int step=0;//步数
memset(vis,0,sizeof(vis));//重置清零操作
//处理特殊情况
if(bx==ex && by==ey)
{
return 0;
}
q.push({bx,by});//起点入队列
vis[bx][by]=true;//更新标记
while(q.size())
{
int sz=q.size();
step++;
while(sz--)
{
auto [a,b]=q.front();
q.pop();
for(int i=0;i<4;i++)
{
int x=a+dx[i],y=b+dy[i];
if (x >= 0 && x < m && y >= 0 && y < n && vis[x][y] == false &&forest[x][y])
{
if (x == ex && y == ey)
{
return step;
}//成功情况
q.push({x,y});
vis[x][y]=true;
}
}
}
}
return -1;//未成功找到
}
int cutOffTree(vector<vector<int>>& forest) {
m=forest.size(),n=forest[0].size();
vector<pair<int,int>> trees;
//存储树节点
for(int i=0;i<m;i++)
{
for(int j=0;j<n;j++)
{
if(forest[i][j]>1)
{
trees.push_back({i,j});
}
}
}
//排序
sort(trees.begin(),trees.end(),[&](const pair<int,int>& a,const pair<int,int>& b)
{
return forest[a.first][a.second]<forest[b.first][b.second];
});
int bx=0,by=0;//起点
for(auto& [a,b] :trees)
{
int temp=bfs(forest,bx,by,a,b);
if(temp==-1)
{
return -1;
}//无法砍完所有的树
ret+=temp;//累加
bx=a,by=b;//更新起点
}
return ret;
}
};BFS 的温柔之处在于它不争先、不冒进,它平等地探寻每一层的可能性,直到在无声处,找到了那条最短的归途。
在信息爆炸的时代,BFS 的这种秩序与理性,正是一种诗意的坚持。它提醒我们:有时候,最直接的路径,并非要靠孤勇闯荡,而是要靠层层递进的耐心与细致的规划。
愿我们都能在迷宫般的生活中,走出属于自己的最短路径。
本篇关于bfs算法求取最短路径的介绍就暂告段落啦,希望能对大家的学习产生帮助,欢迎各位佬前来支持斧正!!!