本文介绍BFS
dfs可以参考:深度优先搜索(DFS)
bfs旨在面临一个路口时,把所有的岔路口都记下来,然后选择其中一个进入,然后将它的分路情况记录下来,然后再返回来进入另外一个岔路,并重复这样的操作,具有盲目性。因此其算法复杂度与集合总数密切相关,一般BFS算法常用于求最短的步数或者求扩散性质的区域问题。(求最长什么的(去盲目搜索,可能会爆TLE或者MLE)
需要工具:队列queue(STL之队列)
一个标记是否访问过该状态的数组
建立一个队列->储存起点(标记起点为访问过)->进入while(!q.empty())循环(每次取出队首元素(用一个临时变量存储他的信息,然后就可以把他从队列删除了),存储他周围没有走过的路到队列中,然后标记这个状态出现过(保证不会再重复这种状态)->直到队列不再有元素或者遍历到目标就可以结束了(只要遍历到目标,绝对是最优解,因为距离(步数)是一直在增加的,越往后不可能是最优解)
杯子最后是一人一半水,因为有一个杯子容积小于一半,所以他最后肯定是0,那么我们让vcup[1]杯子容量最大,v[2]第二大,那么最后答案肯定是v[1]==v[2]&&v[3]==0就成立
倒水需要的工具:1,vcup[i]记录杯子体积, 2,一个结构体储存每个状态信息 3,一个怎么倒水的函数 4,一个book[N][N][N]来标记某个状态是否访问过
#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();
}
}
Sample Input
7 8 #.#####. #.a#..r. #..#x... ..#..#.# #...##.. .#...... ........
13
走迷宫需要的工具:1,book[i][i]标记该位置是否来过 2,走路方法的基向量(有的题可能一步可以走几格,所以我们建立这个方向的基向量
int way[5][5] = { {1,0},{-1,0},{0,1},{0,-1} };
3,一个结构体储存当前位置与走了几步 4,一个a[i][j]记录该位置信息(是路还是障碍还是什么)
#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基本方法与思想了