[算法学习日志04]

本文介绍了如何利用深度优先搜索(DFS)和广度优先搜索(BFS)算法解决字符矩阵中寻找八连块和计算阿尔吉侬吃奶酪最短路径的问题,展示了两种搜索策略在解决路径问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

怀追求卓越之心,开启终身成长的人生游戏 

例题一(DFS)

        题目描述:输入一个 m行n列的字符矩阵,统计字符“@”组成多少个八连块。如果两个字符“@”所在的各自相邻(横、竖或者斜对角线方向),就说他们同属于一个八连块。(示例,图中有两个八连块)

*    *    *   *  @

*   @  @  *  @

*   @   *   *  @

@ @ @  *  @

#include <iostream>
#include <cstdio>
#include <cstring>
#include <algorithm>

using namespace std;

const int N=1010;

int m,n;
char p[N][N];
int flag[N][N];

void dfs(int x,int y,int num){
    //1.边界判断(递归的推出条件)
    if(x>=m||x<0||y>=n||y<0) return;
    //2.是否访问过以及是否符合判断标准
    if(flag[x][y]!=0||p[x][y]!='@') return;
    //3.通过num即下面的cnt来表示这个属于哪一堆
    flag[x][y]=num;
    //4.开始递归 通过-1 0 1 双重循环来遍历上下左右八个格子
    //当i j都等于0时表示自己
    for(int i=-1;i<=1;i++){
        for(int j=-1;j<=1;j++){
            if(i!=0&&j!=0) dfs(x+i,y+j,num);
        }
    }

}

int main()
{
    //1.通过scanf的放回值来判断输入是否正确
    while(scanf("%d%d",&m,&n)==2&&m!=0&&n!=0)
    {
        //2.通过%s来输入一行,不用两层循环来,减少复杂度
        for(int i=0;i<m;i++) scanf("%s",p[i]);
        //3.通过memset来初始化
        memset(flag,0,sizeof(flag));
        int cnt=0;
        for(int i=0;i<m;i++)
        {
            for(int j=0;j<n;j++)
            {
                if(flag[i][j]==0&&p[i][j]=='@') dfs(i,j,++cnt);
            }
        }
        cout<<cnt<<endl;
    }

    return 0;
}
  • scanf 函数的返回值可以分成三种情况

  1. 正整数,表示正确输入参数的个数。例如执行 scanf("%d %d", &a, &b); 

  2. 如果用户输入"3 4",可以正确输入,返回2(正确输入了两个变量);如果用户输入"3,4",可以正确输入a,无法输入b,返回1(正确输入了一个变量)。    

  3. 0,表示用户的输入不匹配,无法正确输入任何值。如上例,用户如果输入",3 4",返回0。

  4. EOF,这是在stdio.h里面定义的常量(通常值为-1),表示输入流已经结束。

例题二(BFS) 

        题目描述:阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。

        现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。

        迷宫用一个 R×C 的字符矩阵来表示。

        字符 S 表示阿尔吉侬所在的位置,字符 表示奶酪所在的位置,字符 # 表示墙壁,字符 . 表示可以通行。

        阿尔吉侬在 1 个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。

        输入格式

        第一行是一个正整数 T,表示一共有 T 组数据。

        每一组数据的第一行包含了两个用空格分开的正整数 R 和 C 表示地图是一个 R×C  的矩阵。

        接下来的 R行描述了地图的具体内容,每一行包含了 C个字符。字符含义如题目描述中所述。保证有且仅有一个 S 和 E。

        输出格式

        对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。

        若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。

        每组数据的输出结果占一行。

        数据范围

        1<T≤10
        2≤R,C≤200

        输入样例:
3
3 4
.S..
###.
..E.
3 4
.S..
.E..
....
3 4
.S..
####
..E.
        输出样例:
5
1
oop!
#include <iostream>
#include <cstdio>
#include <algorithm>
#include <cstring>
#include <queue>

using namespace std;

#define x first
#define y second

const int N = 210;

typedef pair<int,int> PII;

int t,r,c;
char p[N][N];
int step[N][N];

//用数组来表示方向的转变
int dx[4]={-1,0,1,0};
int dy[4]={0,-1,0,1};

//bfs的函数
int bfs(PII start,PII end)
{
    queue<PII> q;
    //用menset初始化dist数组,-1表示没有被访问过
    memset(step,-1,sizeof step); 
    
    step[start.x][start.y] = 0; //标记并记录步数
    q.push(start);
    
    while(q.size())
    {
        auto t = q.front();
        q.pop();
        
        for(int i = 0;i<4;i++)
        {
            int x=t.x+dx[i],y=t.y+dy[i];
            
            //限制条件的判断 出界 障碍物 访问过
            if(x<0||x>=r||y<0||y>=c) continue;
            if(p[x][y]=='#') continue;
            if(step[x][y]!=-1) continue;
            
            step[x][y] = step[t.x][t.y]+1;
            
            if(end == make_pair(x,y)) return step[x][y];
            
            q.push({x,y});
        }
    }
    
    return -1;
}


int main()
{
    //1.输入数据
    scanf("%d",&t);
    for(int i=1;i<=t;i++) //while(t--)
    {
        scanf("%d%d",&r,&c);
        for(int j = 0;j<r;j++) scanf("%s",p[j]);
        
        //2.标记好终点和起点
        PII start,end;
        for(int j=0;j<r;j++)
            for(int k=0;k<c;k++)
                if(p[j][k]=='S') start = {j,k};
                else if (p[j][k]=='E') end = {j,k};
        
        //3.调用函数开始搜索
        int distance=bfs(start,end);
        //4.输出结果
        if(distance == -1) puts("oop!");
        else printf("%d\n",distance);
        
    }
    
    return 0;
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值