3.9广度优先搜索bfs
3.9广度优先搜索bfs
洛谷题目传送门
P1451 求细胞数量
【题目描述】
一矩形阵列由数字 0 到 9 组成,数字 1 到 9 代表细胞,
细胞的定义为沿细胞数字上下左右若还是细胞数字则为同一细胞,
求给定矩形阵列的细胞个数。
【输入格式】
第 1 行两个整数代表矩阵大小 n 和 m。
接下来 n 行,每行一个长度为 m 的只含字符 0 到 9 的字符串,代表这个 n×m 的矩阵。
【输出格式】
一行一个整数代表细胞个数。
输入样例:
4 10
0234500067
1034560500
2045600671
0000000089
输出样例: 4
数据规模与约定:对于 100% 的数据,保证 1≤n,m≤100。
【参考题解】
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char a[N][N];
int n,m,ans=0;
int dx[8]={-1, 0, 1, 0};
int dy[8]={ 0,-1, 0, 1};
bool in(int x, int y){
if(x>=0&&x<n&&y>=0&&y<m) return 1;
return 0;
}
struct T{
int x,y;
};
void bfs(int x, int y){
queue<T> que; que.push((T){x,y}); a[x][y]='0';
while(!que.empty()){
T temp=que.front(); que.pop();
for(int i=0; i<4; i++){
int tx=temp.x+dx[i];
int ty=temp.y+dy[i];
if(in(tx,ty) && a[tx][ty]!='0'){
que.push((T){tx,ty}); a[tx][ty]='0';
}
}
}
}
int main(){
// freopen("data.in", "r", stdin);
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) {
scanf("%s", a[i]);
}
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(a[i][j]!='0'){
bfs(i,j); ans++;
}
}
}
printf("%d\n", ans);
return 0;
}
P1596 [USACO10OCT]Lake Counting S
【题目描述】
由于近期的降雨,雨水汇集在农民约翰的田地不同的地方。
我们用一个 NxM(1<=N<=100;1<=M<=100) 网格图表示。
每个网格中有水('W') 或是旱地('.')。
一个网格与其周围的八个网格相连,而一组相连的网格视为一个水坑。
约翰想弄清楚他的田地已经形成了多少水坑。
给出约翰田地的示意图,确定当中有多少水坑。
【输入格式】
第 1 行, 两个空格隔开的整数:N 和 M ,
第 2 行到第 N+1 行, 每行 M 个字符,每个字符是 'W' 或 '.',它们表示网格图中的一排。
字符之间没有空格。
【输出格式】
一行,水坑的数量
输入样例:
10 12
W........WW.
.WWW.....WWW
....WW...WW.
.........WW.
.........W..
..W......W..
.W.W.....WW.
W.W.W.....W.
.W.W......W.
..W.......W.
输出样例: 3
【参考题解】
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char a[N][N];
int n,m,ans=0;
int dx[8]={-1,-1,-1, 0, 0, 1, 1, 1};
int dy[8]={-1, 0, 1,-1, 1,-1, 0, 1};
bool in(int x, int y){
if(x>=0&&x<n&&y>=0&&y<m) return 1;
return 0;
}
struct T{
int x,y;
};
void bfs(int x, int y){
queue<T> que; que.push((T){x,y}); a[x][y]='.';
while(!que.empty()){
T temp=que.front(); que.pop();
for(int i=0; i<8; i++){
int tx=temp.x+dx[i];
int ty=temp.y+dy[i];
if(in(tx,ty) && a[tx][ty]=='W'){
que.push((T){tx,ty}); a[tx][ty]='.';
}
}
}
}
int main(){
// freopen("data.in", "r", stdin);
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) {
scanf("%s", a[i]);
}
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(a[i][j]=='W'){
bfs(i,j); ans++;
}
}
}
printf("%d\n", ans);
return 0;
}
UVA572 油田 Oil Deposits
【题目描述】
输入多个 m 行 n 列的矩阵,用 0 0 表示输入结束。
找出有多少块石油区域,用 “@” 代表石油,假如两个 “@” 在横,竖或对角线上相邻,
就说它们位于同一区域,对于每个输入,输出一个数表示有几个石油区域。
输入样例:
1 1
*
3 5
*@*@*
**@**
*@*@*
1 8
@@****@*
5 5
****@
*@@*@
*@**@
@@@*@
@@**@
0 0
输出样例:
0
1
2
2
【参考题解】
#include<bits/stdc++.h>
using namespace std;
const int N=110;
char a[N][N];
int n,m,ans=0;
int dx[8]={-1,-1,-1, 0, 0, 1, 1, 1};
int dy[8]={-1, 0, 1,-1, 1,-1, 0, 1};
bool in(int x, int y){
if(x>=0&&x<n&&y>=0&&y<m) return 1;
return 0;
}
struct T{
int x,y;
};
void print(){
for(int i=0; i<n; i++) printf("%s\n",a[i]);
printf("\n");
}
void bfs(int x, int y){
queue<T> que; que.push((T){x,y}); a[x][y]='*';
while(!que.empty()){
T temp=que.front(); que.pop();
for(int i=0; i<8; i++){
int tx=temp.x+dx[i];
int ty=temp.y+dy[i];
if(in(tx,ty) && a[tx][ty]=='@'){
que.push((T){tx,ty}); a[tx][ty]='*';
}
}
}
}
int main(){
// freopen("data.in", "r", stdin);
while(scanf("%d%d", &n, &m)==2){
if(n==0&&m==0) return 0;
for(int i=0; i<n; i++) {
scanf("%s", a[i]);
}
ans=0; //多组数据,每次都需要初始化为 0
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(a[i][j]=='@'){
bfs(i,j); ans++;
// print(); //输出调试
}
}
}
printf("%d\n", ans);
}
return 0;
}
P1443 马的遍历
【题目描述】
有一个 n × m 的棋盘,在某个点 (x,y) 上有一个马,
要求你计算出马到达棋盘上任意一个点最少要走几步。
【输入格式】
输入只有一行四个整数,分别为 n, m, x, y。
【输出格式】
一个 n ×m 的矩阵,代表马到达某个点最少要走几步
(左对齐,宽 5 格,不能到达则输出 -1)。
输入样例:3 3 1 1
输出样例:
0 3 2
3 -1 1
2 1 4
数据规模与约定:对于全部的测试点,保证 1 ≤x ≤n ≤400,1 ≤y ≤m ≤400。
#include<bits/stdc++.h>
using namespace std;
int n, m, x, y;
const int N=410;
int ans[N][N];
struct T{
int x, y, step;
};
int dis[][2]={
{-2,-1},{-1,-2},{ 1,-2},{ 2,-1},
{ 2, 1},{ 1, 2},{-1, 2},{-2, 1}};
bool in (int x, int y){
if(x>=1 &&x<=n &&y>=1 && y<=m) return 1;
return 0;
}
void print(){
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
cout<<left<<setw(5)<<ans[i][j];
}cout<<endl;
}cout<<endl;
}
void bfs(int x, int y){
int step=0;
queue<T> que; que.push((T){x,y,step});
ans[x][y]=0;
while(!que.empty()){
T temp=que.front(); que.pop();
for(int i=0; i<8; i++){
int tx=temp.x+dis[i][0];
int ty=temp.y+dis[i][1];
if(in(tx,ty) && ans[tx][ty]==-1){
ans[tx][ty]=temp.step+1;
que.push((T){tx,ty,ans[tx][ty]});
}
}
}
}
int main(){
cin>>n>>m>>x>>y;
for(int i=1; i<=n; i++){
for(int j=1; j<=m; j++){
ans[i][j]=-1;
}
}
bfs(x, y);
print();
return 0;
}
马的遍历2
【题目描述】
中国象棋的规则是马走“日”,现在有一个 8*8 的棋盘,某个格子里放有一个马。
现在指定一个目标点, 你的任务是判定在给定步数内能否移动这个马到指定的目标点。
注意:马不能走到棋盘外的点,因此靠近边界的马并不能到达所有的点,棋盘上的点横纵坐标均从 1 计数。
【输入格式】
第一行两个坐标 x,y,c,(x,y)表示马的起始位置,c 表示最多走几步
第二行两个坐标 a,b,表示马将要到达的位置
【输出格式】
输出一行 yes 或 no 表示可以或不可以实现
输入样例
1 1 1
2 3
输出样例:yes
输入样例
1 1 3
8 8
输出样例:no
测试点数据范围:
对于50%的数据: 1 <= c <= 5
对于100%的数据: 1 <= c <= 25
【参考题解】
#include<iostream>
#include<queue>
using namespace std;
const int N=30;
int vis[N][N];
int dis[][2]={
{-2, -1},{-1,-2},{ 1,-2},{ 2,-1},
{ 2, 1},{ 1, 2},{-1, 2},{-2, 1}};
bool in(int x,int y){
if(x>=1 && x<=8 && y>=1 && y<=8) return 1;
return 0;
}
struct T{
int x,y,step;
};
queue<T> que;
void bfs(int x, int y, int step){
que.push((T){x,y,step});
while(!que.empty()){
T temp = que.front(); que.pop();vis[temp.x][temp.y]=1;
for(int i=0; i<8; i++){
int tx=temp.x+dis[i][0];
int ty=temp.y+dis[i][1];
if(in(tx,ty) && temp.step>0 && !vis[tx][ty]){
que.push((T){tx,ty,temp.step-1});
}
}
}
}
int main(){
freopen("horse.in", "r", stdin);
freopen("horse.out", "w", stdout);
int x,y,c,a,b;
cin>>x>>y>>c>>a>>b;
bfs(x,y,c);
if(vis[a][b]) cout<<"yes";
else cout<<"no";
return 0;
}
Catch That Cow
http://poj.org/problem?id=3278
【题目描述】
给定两个整数 N 和 K,
可以通过三种操作: N+1, N-1, N*2, 使得 N==K.
求最少的操作次数。
输入样例:5 17
输出样例:4
样例解释:5 * 2 - 1 * 2 - 1
【参考题解】
#include<iostream>
#include<cstdio>
#include<queue>
using namespace std;
struct T{
int n,k,step;
};
// 5-> 17
// 5 * 2 -1 *2 -1
int bfs(int n, int k){
queue<T> que; que.push((T){n,k,0});
while(!que.empty()){
T temp=que.front(); que.pop();
// printf("n=%d\t k=%d\t step=%d\n", temp.n, temp.k, temp.step);
if(temp.n==temp.k){
return temp.step;
}else if(temp.n>temp.k){
que.push((T){temp.n-1, k, temp.step+1});
}else if(temp.n<temp.k){
que.push((T){temp.n-1, k, temp.step+1});//需要
que.push((T){temp.n+1, k, temp.step+1});
que.push((T){temp.n*2, k, temp.step+1});
}
}
}
int main(){
// freopen("data.in", "r", stdin);
int n,k; scanf("%d%d", &n, &k);
int ans = bfs(n,k);
printf("%d\n", ans);
return 0;
}
骑士的拯救行动
【问题描述】
公主被关押在一个 N * M 的矩阵牢房中,英勇的 Hacker 骑士决定去拯救公主。
我们假设拯救成功的表示是“骑士到达了公主所在的位置”。
由于在通往公主所在位置的道路中可能遇到守卫,骑士一旦遇到守卫,必须杀死守卫才能继续前进。
骑士可以向上、下、左、右四个方向移动,每移动一个位置需要 1 个单位时间,
杀死一个守卫需要花费额外的 1 个单位时间。骑士足够强壮,有能力杀死所有的守卫。
给定牢房矩阵,公主、骑士和守卫在矩阵中的位置,请你计算拯救行动成功需要花费最短时间。
【输入格式】
第 1 行有两个整数代表 N 和 M。
随后 N 行,每行有 M 个字符。
"@"代表道路,"a"代表公主,"r"代表骑士,"x"代表守卫, "#"代表墙壁。
【输出格式】
如果拯救行动成功,输出一个整数,表示行动的最短时间。
如果不可能成功,输出 "Impossible"。
输入样例:
7 8
#@#####@
#@a#@@r@
#@@#x@@@
@@#@@#@#
#@@@##@@
@#@@@@@@
@@@@@@@@
输出样例:13
数据范围:N,M <= 20
【参考题解】
#include<iostream>
#include<queue>
#include<cstdio>
using namespace std;
const int N=110;
char a[N][N];
bool vis[N][N];
int dis[][2]={{-1, 0},{ 0,-1},{ 1, 0},{ 0, 1}};
int n,m;
int x1,y1,x2,y2,f=0;
struct T{
int x,y,step;
};
bool in(int x, int y){
if(x>=0&&x<n&&y>=0&&y<m) return 1;
return 0;
}
int bfs(int x, int y){
queue<T> que; que.push((T){x,y,0});
while(!que.empty()){
T temp=que.front(); que.pop(); vis[temp.x][temp.y]=1;
for(int i=0; i<4; i++){
int tx=temp.x+dis[i][0];
int ty=temp.y+dis[i][1];
if(in(tx,ty) && a[tx][ty]!='#' && !vis[tx][ty]){
if(a[tx][ty]=='a') return temp.step+1;
if(a[tx][ty]=='@') que.push((T){tx,ty,temp.step+1});
if(a[tx][ty]=='x') que.push((T){tx,ty,temp.step+2});
}
}
}
return -1;//不能到达
}
int main(){
// freopen("data.in", "r", stdin);
scanf("%d%d", &n, &m);
for(int i=0; i<n; i++) scanf("%s", a[i]);
for(int i=0; i<n; i++){
for(int j=0; j<m; j++){
if(a[i][j]=='r') x1=i, y1=j, f++;
if(a[i][j]=='a') x2=i, y2=j, f++;
if(f==2) {
int ans=bfs(x1,y1);
if(ans!=-1) printf("%d\n", ans);
else printf("Impossible\n");
return 0;
}
}
}
return 0;
}