BFS英文全稱是Breadth First Search。
廣度優先搜索使用隊列(queue)來實現,整個過程也可以看做一個倒立的樹形:
1、把根節點放到隊列的末尾。
2、每次從隊列的頭部取出一個元素,查看這個元素所有的下一級元素,把它們放到隊列的末尾。並把這個元素記爲它下一級元素的前驅。
3、找到所要找的元素時結束程序。
4、如果遍歷整個樹還沒有找到,結束程序。
隊列使用詳見:STL內置函數用法詳解——五、queue(提示:可在博客內容的右側菜單欄中找到目錄方便快速查找)
BFS()
{
初始化隊列
while(隊列不爲空且未找到目標節點)
{
取隊首節點擴展,並將擴展出的非重複節點放入隊尾;
必要時記住每個節點的父節點;
}
}
void bfs(起始點)
{
將起始點放入隊列中;
標記起點已訪問;
while(隊列不爲空)
{
訪問隊列中首元素x;
刪除隊首元素;
for(x所有相鄰點)
{
if(該點未被訪問過且合法)
將該點加入隊列末尾;
}
}
隊列爲空,廣搜結束;
}
一、抓住這頭牛
題目描述:
農夫知道一頭牛的位置,想要抓住它。農夫和牛都位於數軸上,農夫起始位於點N(0<=N<=100000),牛位於點K(0<=K<=100000)。農夫有兩種移動方式:
1、從X移動到X-1或X+1,每次移動花費一分鐘
2、從X移動到2*X,每次移動花費一分鐘
假設牛沒有意識到農夫的行動,站在原地不動。農夫最少要花多少時間才能抓住牛?
輸入:
農夫的起始位置N,爲牛的位置K
代碼如下:
#include<iostream>
#include<cstring>
#include<queue>
using namespace std;
int N,K; //N爲農夫的起始位置,K爲牛的位置
const int MAXN=100000;
int visited[MAXN+10];
struct Step{
int x; //位置
int steps; //到達x所需步數
Step(int xx,int s):x(xx),steps(s){}
/*
Step(int xx,int s):x(xx),steps(s){} 爲Step結構體的構造函數
等價於
Step(int xx,int s)
{
x=xx;
steps=s;
}
*/
};
queue<Step> q; //隊列,即Open表
int main()
{
cin>>N>>K;
memset(visited,0,sizeof(visited));
q.push(Step(N,0));
visited[N]=1;
while(!q.empty())
{
Step s=q.front();
if(s.x==K) //找到目標
{
cout<<s.steps<<endl;
return 0;
}
else
{
if(s.x-1>=0&&!visited[s.x-1])
{
q.push(Step(s.x-1,s.steps+1));
visited[s.x-1]=1;
}
if(s.x+1<=MAXN&&!visited[s.x+1])
{
q.push(Step(s.x+1,s.steps+1));
visited[s.x+1]=1;
}
if(s.x*2<=MAXN&&!visited[s.x*2])
{
q.push(Step(s.x*2,s.steps+1));
visited[s.x*2]=1;
}
q.pop();
}
}
return 0;
}
補充說明 結構體中使用構造函數初始化 :
構造函數:
struct Student{
string name;
int score;
Student(string n,int s)
{
name=n;
score=s;
}
};
語法上,構造函數具有以下性質:
1、函數體名與結構體名完全相同
2、不能定義返回值類型,也不能有return語句
3、可以有形參,也可以沒有,可以帶默認參數
4、可以重載默認構造函數:
struct Student{
string name;
int score;
Student() {}
};
注意:同一個結構體中,不能出現兩個默認構造函數。初始化列表:
struct Student{
string name;
int score;
Student() {} //注意不可省略默認構造函數
Student(string n,int s):name(n),score(s) {}
};
二、迷宮
三、密碼鎖
題目描述:
現在一個緊急的任務是打開一個密碼鎖。 密碼由四位數字組成,每個數字從1到9進行編碼。每次可以對任何一位數字加1或減1。當將9加1時,數字將變爲1,當將1減1時,數字將變爲9.你也可以交換相鄰數字,每一個行動記作異步。現在你的任務是使用最小的步驟來打開鎖。注意:最左邊的數字不與最右邊的數字相鄰。
輸入:
第一行輸入四個數字,表示密碼鎖的初始狀態。
第二行輸入四個數字,表示開鎖的密碼。
輸出:
最小步數:
代碼如下:
#include<iostream>
#include<cstring>
#include<queue>
#include<cstdio>
using namespace std;
struct node{
int num[4],step;
}first,last;
int vis[11][11][11][11];
void bfs()
{
int i;
node a,next;
queue<node> q;
a=first;
a.step=0;
q.push(a);
memset(vis,0,sizeof(vis));
vis[a.num[0]][a.num[1]][a.num[2]][a.num[3]]=1;
while(!q.empty())
{
a=q.front();
q.pop();
if(a.num[0]==last.num[0]&&a.num[1]==last.num[1]&&a.num[2]==last.num[2]&&a.num[3]==last.num[3])
{
printf("%d\n",a.step);
return;
}
for(i=0;i<4;++i) //+1
{
next=a;
++next.num[i];
if(next.num[i]==10)
next.num[i]=1;
if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]])
{
vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
++next.step;
q.push(next);
}
}
for(i=0;i<4;++i) //-1
{
next=a;
--next.num[i];
if(next.num[i]==0)
next.num[i]=9;
if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]])
{
vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
++next.step;
q.push(next);
}
}
for(i=0;i<3;++i) //交換
{
next=a;
next.num[i]=a.num[i+1];
next.num[i+1]=a.num[i];
if(!vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]])
{
vis[next.num[0]][next.num[1]][next.num[2]][next.num[3]]=1;
++next.step;
q.push(next);
}
}
}
}
int main()
{
int i,j;
for(i=0;i<4;++i)
scanf("%d",&first.num[i]);
for(i=0;i<4;++i)
scanf("%d",&last.num[i]);
bfs();
return 0;
}