文章目录
总结:
BFS主要用来解决求“次数”“最小次数”“个数”等问题
要素:结构体、队列 、方向与判定
求次数要记得在结构体中定义变量用来存储每一步对应的次数值。
洛谷P1032
这题字符串+BFS
#include <bits/stdc++.h>
using namespace std;
#define num 10
string a, b;
string ason[num], atr[num];
int n, ans;
struct node
{
string str;
int step;
};
queue<node> q;
map<string, int> vis; //标记
string splice(string &str, int i, int j)
{
string back = "";
if (i + ason[j].length() > str.length()) //确认拼接长度是否超出
return back;
for (int k = 0; k < ason[j].length(); k++) //确认是否符合对应规则子串
if (str[i + k] != ason[j][k])
return back;
back = str.substr(0, i); //取规则子串前字符
back += atr[j]; //取按规则转换后的字符
back += str.substr(i + ason[j].length()); //取规则子串后字符
return back;
}
void bfs()
{
node s;
s.str = a;
s.step = 0;
q.push(s);
while (!q.empty())
{
node t = q.front();
q.pop();
if (vis[t.str]) //剪枝
continue;
if (t.str == b) //转换完成
{
ans = t.step;
break;
}
vis[t.str] = 1; //标记已使用
string temp;
for (int i = 0; i < t.str.length(); i++) //遍历 从每个字母开始
for (int j = 0; j < n; j++) //从每个字母开始遍历n种转换规则
{
temp = splice(t.str, i, j);
if (temp != "")
{
node t2;
t2.str = temp;
t2.step = t.step + 1;
q.push(t2);
}
}
}
if (ans > 10 || ans == 0)
cout << "NO ANSWER!" << endl;
else
cout << ans << endl;
}
int main()
{
cin >> a >> b;
while (cin >> ason[n] >> atr[n])
n++;
bfs();
//system("pause");
return 0;
}
A.湖计数-搜索
(A\F\G\J题都差不多,BFS模板题)
#include <bits/stdc++.h>
using namespace std;
char str[101][101];
int n, m, ans;
struct node
{
int x;
int y;
};
queue<node> q;
int xx[8] = {1, -1, 0, 0, 1, -1, 1, -1};
int yy[8] = {0, 0, 1, -1, 1, -1, -1, 1};
void bfs(int x, int y)
{
q.push({x, y});
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
str[x][y] = '.';
for (int i = 0; i < 8; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && str[tx][ty] != '.')
{
q.push({tx, ty});
str[tx][ty] = '.';
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
cin >> str[i] + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (str[i][j] == 'W')
{
bfs(i, j);
ans++;
}
}
printf("%d\n", ans);
//system("pause");
return 0;
}
B.01迷宫-搜索
这题正常做会TLE。
推知,如示例
01
10
此类连通区域,不管从哪一个位置开始数,答案都是一样的(4)
所以我们可以把各个块的答案记录下来
#include <bits/stdc++.h>
using namespace std;
int n, m, x, y;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
char str[1001][1001];
bool vis[1001][1001];
int piece[1001][1001], cnt;//用于记录块的图,cnt为块的计数器
int ans[100005];//保存每个块的答案数
struct node
{
int x, y;
};
queue<node> q;
void bfs(int x, int y)
{
q.push({x, y});
vis[x][y] = 1;
piece[x][y] = cnt;//这个点在第cnt个块
ans[piece[x][y]]++;//第cnt个块的答案数+1
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= n && vis[tx][ty] == 0)
{
if (str[tmp.x][tmp.y] != str[tx][ty])
{
q.push({tx, ty});
vis[tx][ty] = 1;
piece[tx][ty] = cnt;
ans[piece[tx][ty]]++;
}
}
}
}
cnt++;//不要忘记!
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
scanf("%s", str[i] + 1);
while (m--)
{
scanf("%d%d", &x, &y);
if (vis[x][y] == 0)//如果为0则说明这是一个“新块”,查一遍
bfs(x, y);
printf("%d\n", ans[piece[x][y]]);//点在哪一个块内就输出该块的答案
}
//system("pause");
return 0;
}
C.营救-搜索
这题莫名其妙卡了我很久,一直wa,究其原因我发现了下面这个玄学问题
查看原文点此
ios+cin+printf混用可过;
ios+cin+scanf是会出问题的
#include <bits/stdc++.h>
using namespace std;
char str[1005][1005];
int n, ans;
int st1, st2, ed1, ed2;
struct node
{
int x;
int y;
int step;//这题求最小步数,结构体内需要记录每一个位置的当前步数
};
queue<node> q;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
int bfs(int st1, int st2, int ed1, int ed2)
{
q.push({st1, st2, 0});
str[st1][st2] = '1';
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
if (tmp.x == ed1 && tmp.y == ed2)
return tmp.step;
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= n && str[tx][ty] == '0')
{
q.push({tx, ty, tmp.step + 1});
str[tx][ty] = '1';
}
}
}
}
int main()
{
ios::sync_with_stdio(false);//用了ios输入全用cin!!!
cin >> n;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= n; j++)
cin >> str[i][j];
cin >> st1 >> st2 >> ed1 >> ed2;
ans = bfs(st1, st2, ed1, ed2);
cout << ans << endl;
//system("pause");
return 0;
}
D.面积(area)-搜索
思路:在整个图的外层加上一圈0,在从(0,0)开始BFS把所有的0变为1(这样外面的0全部成了1),再数一遍有多少个0就行了
#include <bits/stdc++.h>
using namespace std;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
int str[15][15];
struct node
{
int x, y;
};
queue<node> q;
void bfs(int x, int y)
{
q.push({x, y});
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 0 && tx <= 11 && ty >= 1 && ty <= 11 && str[tx][ty] == 0)
{
q.push({tx, ty});
str[tx][ty] = 1;
}
}
}
}
int main()
{
for (int i = 0; i < 12; i++)
{
str[0][i] = 0;
str[11][i] = 0;
}
for (int i = 0; i < 12; i++)
{
str[i][0] = 0;
str[i][11] = 0;
}
for (int i = 1; i <= 10; i++)
for (int j = 1; j <= 10; j++)
scanf("%d", &str[i][j]);
bfs(0, 0);
int ans = 0;
for (int i = 1; i <= 10; i++)
for (int j = 1; j <= 10; j++)
if (str[i][j] == 0)
ans++;
printf("%d\n", ans);
//system("pause");
return 0;
}
E.奇怪的电梯-搜索
#include <bits/stdc++.h>
using namespace std;
int n, a, b, k[501], vis[501];
struct node
{
int x, step;
};
queue<node> q;
int main()
{
int ans = -1;
cin >> n >> a >> b;
for (int i = 1; i <= n; i++)
cin >> k[i];
q.push({a, 0});
vis[a] = 1;
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
if (tmp.x == b)
{
ans = tmp.step;
break;
}
int tx = tmp.x + k[tmp.x];//往上走的情况
if (tx <= n && vis[tx] == 0)
{
q.push({tx, tmp.step + 1});
vis[tx] = 1;
}
tx = tmp.x - k[tmp.x];//往下走的情况
if (tx >= 1 && vis[tx] == 0)
{
q.push({tx, tmp.step + 1});
vis[tx] = 1;
}
}
printf("%d\n", ans);
//system("pause");
return 0;
}
F.猴群-搜索
#include <bits/stdc++.h>
using namespace std;
char str[101][101];
int n, m, ans;
struct node
{
int x;
int y;
};
queue<node> q;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
void bfs(int x, int y)
{
q.push({x, y});
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
str[x][y] = '0';
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && str[tx][ty] != '0')
{
q.push({tx, ty});
str[tx][ty] = '0';
}
}
}
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
cin >> str[i] + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (str[i][j] != '0')
{
bfs(i, j);
ans++;
}
}
printf("%d\n", ans);
//system("pause");
return 0;
}
G.瓷砖-搜索
#include <bits/stdc++.h>
using namespace std;
char str[101][101];
int n, m, ans;
struct node
{
int x;
int y;
};
queue<node> q;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
int bfs(int x, int y)
{
int cnt = 0;
q.push({x, y});
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
cnt++;
str[x][y] = '#';
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && str[tx][ty] != '#')
{
q.push({tx, ty});
str[tx][ty] = '#';
}
}
}
return cnt;
}
int main()
{
scanf("%d%d", &m, &n);
for (int i = 1; i <= n; i++)
cin >> str[i] + 1;
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (str[i][j] == '@')
{
ans = bfs(i, j);
break;
}
}
printf("%d\n", ans);
//system("pause");
return 0;
}
H.林大超市买水果-搜索
这题参考某dalao的用DFS写了……
#include <bits/stdc++.h>
using namespace std;
int m, n, k, price[35], vis[35], f = 0;
typedef long long ll;
void dfs(int tm, int cnt)
{
if (f || cnt > k || tm < 0)//找到了、种数超过了、钱不够了→返回上一层
return;
if (tm == 0)
{
if (cnt == k)
{
f = 1;//可以满足条件
return;
}
return;
}
for (int i = 1; i <= n; i++)
{
if (!vis[i])
{
vis[i] = 1;//标记
dfs(tm - price[i], cnt + 1);//进入下一层
vis[i] = 0;//回溯
}
}
}
int main()
{
scanf("%d%d%d", &m, &n, &k);
ll sum = 0;
for (int i = 1; i <= n; i++)
{
scanf("%d", &price[i]);
sum += price[i];//记和
}
if (k > n || sum < m)//这两种情况直接特判不必搜索
printf("No\n");
else
{
dfs(m, 0);
f == 1 ? printf("Yes\n") : printf("No\n");
}
//system("pause");
return 0;
}
I.逃出迷宫-搜索
(还没写……)
J.最大黑色区域-搜索
#include <bits/stdc++.h>
using namespace std;
int str[101][101];
int n, m, ans;
struct node
{
int x;
int y;
};
queue<node> q;
int xx[4] = {1, -1, 0, 0};
int yy[4] = {0, 0, 1, -1};
int bfs(int x, int y)
{
int cnt = 0;
q.push({x, y});
while (!q.empty())
{
node tmp;
tmp = q.front();
q.pop();
cnt++;
str[x][y] = 0;
for (int i = 0; i < 4; i++)
{
int tx = tmp.x + xx[i];
int ty = tmp.y + yy[i];
if (tx >= 1 && tx <= n && ty >= 1 && ty <= m && str[tx][ty] == 1)
{
q.push({tx,ty});
str[tx][ty] = 0;
}
}
}
return cnt;
}
int main()
{
scanf("%d%d", &n, &m);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
scanf("%d", &str[i][j]);
for (int i = 1; i <= n; i++)
for (int j = 1; j <= m; j++)
{
if (str[i][j] == 1)
{
int cnt = bfs(i, j);
ans = max(ans, cnt);
}
}
printf("%d\n", ans);
//system("pause");
return 0;
}
BFS保存最短路路径并输出
(上图是模拟队列BFS)