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

运行结果:

发布了23 篇原创文章 · 获赞 10 · 访问量 1754

猜你喜欢

转载自blog.csdn.net/weixin_45953673/article/details/104843414
今日推荐