HBリトルソルトフィッシュラーニングレコード*
bfs学習記録:テンプレート/アイデアの要約
少し意見
Lanqiao Cupには検索の質問がたくさんありますが、bfsの質問はほとんどなく、そのほとんどがdfsの質問です。
しかし、昨年、ブルーブリッジカップはBFSテストを受けたので、私はまだ質問をよく研究する必要があります。
bfsはループで検索するため、追跡することはできません。したがって、各ポイントは1回しか歩くことができません。これにより検索が高速化されますが、各ポイントは1回しか歩くことができないため、考えられるすべてのパスを一覧表示することはできません。また、これの利点は迂回を回避することであり、検索結果が見つかったときの最短パスである必要があります。したがって、最短経路の質問のほとんどはbfsを使用します。
「幅優先探索」についての私の理解
bfsは、文字通り、幅優先探索の方法です。検索すると、原点から広がります。dfsが「ある部屋を検索してから別の部屋を検索する」場合、bfsは「各部屋のキャビネットを検索してから各部屋のテーブルを検索する...」この種の詳細な検索です。これにより、アイテムが存在する可能性のある場所の検索が優先され、検索時間が短縮されます。
迷路を「正面、左右」の順に歩くように規定しているように、迷路の出口を探すときは探索と見なすことができます。まず、最初の交差点でどの交差点に行くことができるかを記録し、次にこれらの交差点でどの交差点に行くことができるかを所定の順序(正面左と右)で確認します。途中で訪れた交差点は、繰り返し検査されないようにマークを付ける必要があります。交差点が表示されるまで、それは最後に行くか、それが終わりであり、検索は終了します。私たちが見ているラウンドの数は、最後までの最小ステップ数です。検索プロセスでは、適切なデータ構造を使用して、最短パスである宛先に渡した交差点を格納できます。
このように、検索範囲が広く、目的地までの経路が常に最短経路になります。ただし、欠点は、宛先へのすべてのパスを反復処理できないことです。
bfsの一般的な考え方
まず、前のフラグメントで述べたように、最初に迷路をマークするための2次元配列が必要です。これは、歩くことができるポイントと障害物(歩くことができないポイント)をマークします。
次に、キューを作成し、開始点をキューに追加します。
次に、キューが空でないときにループを実行するように設定されたwhileループを作成します。
ループでは、最初にキューのヘッドノードの座標を取得し、次に移動のルールを指定する必要があります。たとえば、上記の例で指定された「上、左、右」では、2次元配列を使用して、移動後の座標の変更を格納できます。
int direction[4][2] = {
{
0,-1},{
-1,0},{
1,0},{
0,1}};
この配列の4つのデータセットは、それぞれ「上、左、右、下」を表し、座標変換中に実行されます。
int x1=x+direction[a][0];
int y1=y+direction[a][1];
その後、座標の変更を実現できます。この順序で、ヘッドノードの周囲を判断し、可能であれば、変換されたデータポイントをキューに追加します。次に、新しいポイント(x1、y1)の状態を変更して、ここにいることを示します。繰り返しの検索を防ぎます。
最後に、出口が見つかったときにいくつかの情報を停止または返すために、前のステップの終了条件を設定する必要があります。ヘッドノードをループに入れて判断することがよくありますが、ヘッドノードのデータが検索したい情報である場合は、ループを停止します。
bfsの大まかなテンプレート
void BFS(传入的数据)
{
queue<int>q; //建立一个队列
q.push(初始坐标); //把头结点(初始点)加入队列
while(队列不为空)
{
top = q.front(); //取出队首元素top
if(队首元素top就是你要搜索的目标)
{
执行一些操作
return;
}
top.pop(); //将队首元素出队;
for(按顺序寻找top的所有子节点)
{
把可以前往的子节点入队
标记入队的子节点,防止下次重复入队
}
}
}
bfsの例
ブルーブリッジカップXuebaの迷宮
サンプル入力の
入力サンプル1:
3 3
001
100
110
サンプル出力の
出力サンプル1:
4
RDRD
この質問は、bfsの典型的な例と見なすことができます。この質問は、最短のステップ数を要求するだけでなく、最短のパスも出力します。
そこで、キューノードのデータ構造に文字列を追加して、特定のポイントへの最短パスを格納しました。
終点を見つけるときは、最短のステップ数と最短のパスを出力します。
ACコード:
#include<bits/stdc++.h>
using namespace std;
struct data //队列里的数据结构
{
int x; //坐标x
int y; //坐标y
int times; //步数
string road; //走过的路径
data(int a,int b,int d,string c) //构造函数
{
x=a;
y=b;
times=d;
road = c;
}
};
queue<data>datas; //队列用来存放点位数据
bool maps[501][501]; //存放迷宫地图的点位 false代表可前往 true代表不可前往
char fx[] = {
'D','L','R','U'}; //方向ascii码从小到大排列
int site[4][2] = {
{
0,1},{
-1,0},{
1,0},{
0,-1}}; //下 左 右 上的坐标变化
void bfs(int n,int m) //传参为迷宫的大小 n为宽 m为长
{
datas.push(data(1,1,0,"")); //把起始点压入队列
maps[1][1]=true; //标记初始点已走过
while(!datas.empty()) //如果队列不为空
{
data now = datas.front(); //声明一个结构体变量 让now变量指向队列的头结点
datas.pop(); //弹出头结点
//cout<<now.x<<" "<<now.y<<endl;
if(now.x==n&&now.y==m) //如果头结点就是要找的点 就搜索结束
{
cout<<now.times<<endl<<now.road<<endl; //输出走过的路径 和步数
return;
}
for(int temp=0;temp<4;temp++) //开始查找该点的四周点位 (因为只有上下左右4个走法 所以循4次
{
int x1=now.x+site[temp][0]; //变换过的x坐标
int y1=now.y+site[temp][1]; //变换过的y坐标
if(maps[y1][x1]) //如果该点已经走过或者有障碍 跳过
continue;
if(x1<1||y1<1||x1>n||y1>m) //如果坐标超出范围 就跳过此循环
continue;
datas.push(data(x1,y1,now.times+1,now.road+fx[temp])); //把新点位压入队列 路径加上新选择的fx[temp]
maps[y1][x1] = true; //标记已走过
}
}
}
int main()
{
memset(maps,false,sizeof(maps)); //初始化
int x,y; //接收迷宫大小
char input;
cin>>y>>x;
getchar();
for(int y1=1;y1<=y;y1++) //迷宫长
{
for(int x1=1;x1<=x;x1++) //迷宫宽
{
cin>>input;
if(input=='1')
maps[y1][x1]=true; //如果输入是1就标记不可走
}
getchar();
}
bfs(x,y); //bfs 迷宫长宽 与 xy坐标是相反的 所以传反着的坐标
return 0;
}
概要
bfsを使用する場合は、トピックデータに応じて適切なデータ型を選択する必要があります。
BFSの質問では、最短パスの長さを出力できるだけでなく、通常は別のものをもたらすことが多いため、データを格納するための適切な構造を確立する必要があります。
bfsの一般的な環境は、
一般に、重みのないグラフの最短経路を見つけるために使用されます。質問のキーワードは、多くの場合、「到達可能か」と「最短経路」です。
現在、ブルーブリッジカップでのbfsの調査度はdfsよりも低いことが多いですが、近年ではブルーブリッジカップでのbfsの調査も増えているので、よく練習する必要があります。
要するに、より多くの質問をブラッシングし、より多くの経験を蓄積する方が良いです。