BFS入門這一篇就夠了——C++

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) {}
};

二、迷宮

第十屆藍橋杯 試題E:迷宮 —— C++ 超詳解

三、密碼鎖

題目描述:

現在一個緊急的任務是打開一個密碼鎖。 密碼由四位數字組成,每個數字從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;
}

運行結果:

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章