广度优先搜索(BFS)

前言:搜索有俩大几乎万能的法器:DFS与BFS

本文介绍BFS

dfs可以参考:深度优先搜索(DFS)

1,算法特点

bfs旨在面临一个路口时,把所有的岔路口都记下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路,并重复这样的操作,具有盲目性。因此其算法复杂度与集合总数密切相关,一般BFS算法常用于求最短的步数或者求扩散性质的区域问题。(求最长什么的(去盲目搜索,可能会爆TLE或者MLE)

2,算法思路

需要工具:队列queue(STL之队列)

      一个标记是否访问过该状态的数组

建立一个队列->储存起点(标记起点为访问过)->进入while(!q.empty())循环(每次取出队首元素(用一个临时变量存储他的信息,然后就可以把他从队列删除了),存储他周围没有走过的路到队列中,然后标记这个状态出现过(保证不会再重复这种状态)->直到队列不再有元素或者遍历到目标就可以结束了(只要遍历到目标,绝对是最优解,因为距离(步数)是一直在增加的,越往后不可能是最优解)

3,例题一,倒水(求最短步骤)

广度优先搜索(BFS)_第1张图片

思路:这题简直是BFS超级经典,求最短步骤,那么我一直bfs存储状态,步骤数会一直增加,而我一步步摸索,终会得到答案(且一定是最优解)

杯子最后是一人一半水,因为有一个杯子容积小于一半,所以他最后肯定是0,那么我们让vcup[1]杯子容量最大,v[2]第二大,那么最后答案肯定是v[1]==v[2]&&v[3]==0就成立

倒水需要的工具:1,vcup[i]记录杯子体积,    2,一个结构体储存每个状态信息    3,一个怎么倒水的函数      4,一个book[N][N][N]来标记某个状态是否访问过

AC代码

#define _CRT_SECURE_NO_WARNINGS 1
#include 
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int N = 110;

int vcup[5];   //vcupo[i]用于记录第i个杯子的容量
struct cup {
	int v[5];//v[i]表示当前第i个杯子里面水的提体积
	int step;//记录倒水多少次
};
cup head, temp;//俩个变量来储存与判断状态

void pour(int a,int b) {  //这个函数表示a中的水倒入b中
	int sum = temp.v[a] + temp.v[b];  
	if (sum >= vcup[b])temp.v[b] = vcup[b];//如果sum比b杯子容积大,说明a可以把b杯子倒满,可能还有剩
	else temp.v[b] = sum;
	temp.v[a] = sum - temp.v[b];//最后a杯的水就是分配后sum-吧杯的水
}

int book[N][N][N];

void bfs() {
	queueq;
	memset(book, 0, sizeof(book));
	head.v[1] = vcup[1];
	head.v[2] = head.v[3] = head.step = 0;
	book[head.v[1]][head.v[2]][head.v[3]] = 1;//标记起点这个状态已经访问过
	q.push(head);
	while (!q.empty()) {
		head = q.front();//每次取队列第一个,然后判断是否符合目标,是就绝对是最优解
		if (head.v[1] == head.v[2]&&!head.v[3]) {
			cout << head.step << endl; return;//成立后就可以退出,已经得到最优解了
		}
		
		q.pop();//取出来就删掉,先把数据存到head中
		for (int i = 1; i <= 3; ++i)for (int j = 1; j <= 3; ++j) {//这里表示i杯的水倒入j杯
			if (i != j) {//当然不能自己倒入自己
				temp = head; temp.step++;//在整个for(i,j)循环中,每个状态都用temp继承head,然后步骤加一(因为你不能自己用head,否则一个循环走完,明明只加一步,你却加了多步
				pour(i, j);
				if (!book[temp.v[1]][temp.v[2]][temp.v[3]]) {//只有没有标记的状态才可以存入队列中
					book[temp.v[1]][temp.v[2]][temp.v[3]] = 1;
					q.push(temp);
				}
			}
		}
	}//如果队列元素都完了,还没有结果,那就是无解了才会来到这里
	cout << "NO" << endl;
}

int main() {
	int s, n, m;
	while (cin >> s >> n >> m && n + m + s != 0) {
		if (n < m)swap(n, m);
		vcup[1] = s; vcup[2] = n; vcup[3] = m;
		bfs();
	}
}

例题2,迷宫最短路径

广度优先搜索(BFS)_第2张图片

 Sample Input

7 8
#.#####.
#.a#..r.
#..#x...
..#..#.#
#...##..
.#......
........

Sample Output

13

思路,掌握了bfs基本思想的你,肯定不会让每个学生都来bfs一下去找老师的吧(绝对会TLE+MLE双倍快乐的),逆向思维一下,为什么不老师去找学生呢,随便走,bfs找到的第一个就是最优解,不用管找到的是谁

走迷宫需要的工具:1,book[i][i]标记该位置是否来过    2,走路方法的基向量(有的题可能一步可以走几格,所以我们建立这个方向的基向量

int way[5][5] = { {1,0},{-1,0},{0,1},{0,-1} };

3,一个结构体储存当前位置与走了几步    4,一个a[i][j]记录该位置信息(是路还是障碍还是什么)

ACcode

#define _CRT_SECURE_NO_WARNINGS 1
#include 
using namespace std;
#define ll long long
const int INF = 0x3f3f3f3f;
const int N = 210;

int way[5][5] = { {1,0},{-1,0},{0,1},{0,-1} };
int book[N][N];
char a[N][N];

struct teacher {
	int x, y, step;
};
teacher head, temp;//储存当前位置与走了几步

int n, m;//迷宫大小

void bfs() {
	memset(book, 0, sizeof(book));//多test一定记得清空book的访问记录
	book[head.x][head.y] = 1;//标记起点访问过
	queueq;
	q.push(head);
	while (!q.empty()) {
		head = q.front();
		if (a[head.x][head.y] == 'r') {//找到学生就是最优解
			cout << head.step << endl; return;
		}
		q.pop();
		for (int i = 0; i <= 3; ++i) {//i从0开始,不是1,因为我们定义way,下标从0开始
			temp.x = head.x + way[i][0];//我们这里没有直接temp=head,所以step不要忘了继承
			temp.y = head.y + way[i][1];
			temp.step = head.step;
			if (a[temp.x][temp.y] != '#' && !book[temp.x][temp.y] && temp.x >= 1 && temp.x <= n && temp.y >= 1 && temp.y <= m) {//迷宫三大注意条件:不是障碍物,,没有出边界,没有访问过
				book[temp.x][temp.y] = 1;//进来第一件事先标记访问过
				if (a[temp.x][temp.y] == 'x')temp.step += 2;//是警察加2,不是的都加1
				else temp.step++;
				q.push(temp);
			}
		}
	}
	cout << "Poor Dingba has to stay in the prison all his life." << endl;
}

int main() {
	while (cin >> n >> m) {
		for (int i = 1; i <= n; ++i)for (int j = 1; j <= m; ++j) {
			cin >> a[i][j];
			if (a[i][j] == 'a') {
				head.x = i, head.y = j, head.step = 0;  //记录老师位置
			}
		}
		bfs();
	}
	return 0;
}

这俩题,你应该能大概掌握bfs基本方法与思想了

 

 

你可能感兴趣的:(ACM入门基础算法知识,搜索,宽度优先,算法,c++,1024程序员节,蓝桥杯)