每日总结之搜索1.4

这篇博客介绍了广度优先搜索(BFS)的基本模板,并通过两个实例——马走日问题和填涂游戏——进行了详细解析。在马走日问题中,利用BFS寻找从起点到终点的最短步数;在填涂游戏中,BFS用于找出所有连通区域。博客内容包含了算法实现的C++代码,展示了如何构建队列、处理边界和障碍以及如何更新答案矩阵。
摘要由CSDN通过智能技术生成

算法学习

目录

算法学习

广度搜索模板 

1.马走日

2.填涂游戏


广度搜索模板 

int dx[4]={1,0,-1,0};
int dy[4]={0,1,0,-1};//定义坐标偏移量
int sx,sy;//起点x、y坐标
int vis[350][350];//vis数组用来防止同一个点访问多次,true表示已访问,false表示为访问

que.push((point){sx,sy,0});//将起点坐标放入队列,初始步数为0

while(!que.empty())//只要还有可到达点就继续访问,知道榨干它
{
    point f=que.front();//提取出队头
    que.pop();//切记!一定要记得将队头扔掉,否则会死循环

    if(a[f.x][f.y]=='=')//如果当前点就是终点
    {
        cout<<f.t;//输出它,结束~
        return 0;
    }

    for(int i=0;i<=3;i++)//遍历其上下左右相邻的点
    {
        //下面与深搜基本一样
        int nx=x+dx[i];//获取相邻点的x、y坐标
        int ny=y+dy[i]; 
        if(nx>=1&&nx<=n&&ny>=1&&ny<=m&&a[nx][ny]!='#'&&!vis[nx][ny])//判断是否越界、是否撞墙、当前点是否已经被访问过
        {
            que.push((point){nx,ny,f.t+1});//可以走便将其放入队列
            vis[nx][ny]=true;//标记当前点已经走过
        }
    }
}

1.马走日


1.bfs--队列元素设置:x,y,s;横纵坐标和step;

2.方向数组:马走日,8个方向;

3.队列初始化&&head,tail:x,y,s;

4.扩充队尾tail++;

5.起点标记;

6.剪枝干:边界,标记,障碍

7.for循环设置:8个方向选择

8.队首选择某方向走下一步

9.赋给队尾tx,ty,s+1;

10.扩充队尾tail++

11.head++;出队(tail将8个方向尝试后)

#include<stdio.h>
#include<stdlib.h>
#include<math.h>
struct node
{
    int x;                      //横坐标
    int y;                      //纵坐标
    int s;                      //步数step
};
int main()
{
    struct node que[400*400+10];     //结构体,地图至少大小400*400
    int a[401][401];      
    int book[401][401];             
    int bx[]= {1,1,-1,-1,2,2,-2,-2};//马走日
    int by[]= {2,-2,2,-2,1,-1,1,-1};
    int ans[401][401];              //到达每一点所需步数          
    int head=1,tail=1;              //初始化head,tail;
    int n,m,sx,sy;
    scanf("%d %d %d %d",&n,&m,&sx,&sy);
    que[tail].x=sx;                //初始化que队列
    que[tail].y=sy;
    que[tail].s=0;                 //此时位于起点,还没走,step=0;
    tail++;                        //head=1,tail=2;
    book[sx][sy]=1;                //标记起点
    memset(ans,-1,sizeof(ans));    //初始化为-1
    ans[sx][sy]=0;                 //起点为0
    //int flag=0; 
    while(head<tail)              //循环队列条件head<tail
    {
        for(int k=0;k<8;k++)                         //for循环8个方向
        {
            int tx=que[head].x+bx[k];                //注意是que【head】
            int ty=que[head].y+by[k];                //x,y往其中一个方向走
            if(tx<1||ty<1||tx>n|ty>m)continue;       //边界
            if(a[tx][ty]==1||book[tx][ty]==1)continue; //标记和障碍,此题无障碍
            book[tx][ty]=1;                           //标记,但不用取消标记,宽搜每个点只入队一次; 
            que[tail].x=tx;                           //head移给tail
            que[tail].y=ty;                           //head移给tail
            que[tail].s=que[head].s+1;                //tail步数比head多1
            ans[tx][ty]=que[tail].s;                  // 步数赋给ans保存
            tail++;                                   //队列后移
        }
        head++;                                      //出队操作,可尝试方向尝试完后跳出循环;
    }
    for(int i=1;i<=n;i++)
	{
		for(int j=1;j<=m;j++)
		{
			printf("%d ",ans[i][j]);
		}
		printf("\n");
	}
      return 0;
}

2.填涂游戏

P1162 填涂颜色 - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)https://www.luogu.com.cn/problem/P1162


1.关键点:连通块,在已给图形上再套一圈(1-n)--(0,n+1);(逆向思维)已标记的0为不涂色的,未标记的0为涂色的。

2.队列初始化&&head=tail=1:x,y,s=0;(二维数组x,y)+标记起点

3.扩充队尾tail++

4.for循环设置:que[head]选择4个方向

5.插点入队:tx,ty,s+1

6.扩充队尾tail++;

7.该点循环方向选择结束,入队:head++;

 

#include<stdio.h>
struct note
{
    int x;
    int y;
    int s;
} que[2000];
int main()
{

    int n,i,j;
    int a[40][40]= {0};
    //int book[40][40];
    scanf("%d",&n);
    for(i=1; i<=n; i++)                //输入内圈(1,n),整体为(0,n+1),构造连通块;
        for(j=1; j<=n; j++)
        {
            scanf("%d",&a[i][j]);
        }
    int bx[]= {0,0,1,-1};
    int by[]= {1,-1,0,0};
    int head=1,tail=1;
    que[tail].x=1;
    que[tail].y=1;
    que[tail].s=0;
    tail++;
    a[0][0]=2;                         //起点标记
    while(head<tail)
    {
        for(i=0; i<=3; i++)
        {
            int tx=que[head].x+bx[i];        //四个方向
            int ty=que[head].y+by[i];
            if(tx<0||ty<0||tx>n+1||ty>n+1)continue;//排除边界,此时边界为0,n+1;
            //if(a[tx][ty]==-1)continue;
            if(a[tx][ty]==0)                //为空0时
            {
                a[tx][ty]=2;
                que[tail].x=tx;
                que[tail].y=ty;
                que[tail].s=que[head].s+1;
                tail++;
            }
        }
        head++;
    }
    for(i=1; i<=n; i++)
    {
        for(j=1; j<=n; j++)
        {
            if(a[i][j]==0)//未标记输出2
                printf("2 ");
            else if(a[i][j]==2) //标记输出0
                printf("0 ");
            else printf("1 ");//1输出1
        }
        printf("\n");
    }
    return 0;
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值