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;
}
posted @ 2021-12-18 22:32  HelloHeBin  阅读(172)  评论(0编辑  收藏  举报