大一BFS入门

【B题】

抓住奶牛,已知起点求到终点的最少步数,那就是BFS。

只有三种方向:x+1,x-1,x*2.

数的范围是[0,100000];

那么就去用BFS遍历这100000个数;

如果第一次走到了终点,那么这个步数就是最少的步数.

代码如下:

 

#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
int dir[4][2]={-1,0,0,-1,1,0,0,1};
int use[30][30];                                 //标记是否走过这个点
char mp[30][30];                                 //存图
int n,m;
struct node                                      //结构体存点坐标(x,y)
{
    int x;
    int y;
};
int bfs(int sx,int sy)
{
    int cnt=1;                                  //开一个cn 计数
    queue<node> qu;
    memset(use,0,sizeof(use));         // 初始化标记数组,表示图上面的每个点都没有走过  
    node now,next;
    now.x=sx;
    now.y=sy;
    use[sx][sy]=1;
    qu.push(now);                              //起点入队列
    while(!qu.empty())                         //判空
    {
        now=qu.front();                        //取一个点
        qu.pop();
        for(int i=0;i<4;i++)                   //遍历上下左右四个点 
        {
            int dx=now.x+dir[i][0];
            int dy=now.y+dir[i][1];
            if(mp[dx][dy]=='.'&&use[dx][dy]==0&&dx>=0&&dx<n&&dy>=0&&dy<m)    //是否重复走过,并且是能走的点
            {
                use[dx][dy]=1;                                               //标记走过
                cnt++;                                                       //计数+1
                next.x=dx;
                next.y=dy;
                qu.push(next);                                              //现在的点入队列 搜下一个点
            }
        }
    }
    return cnt;
}
int main()
{
    while(scanf("%d%d",&m,&n)!=EOF)
    {
        if(n==0&&m==0)
            break;
        for(int i=0;i<n;i++)
            scanf("%s",mp[i]);
        int x,y;
        for(int i=0;i<n;i++)
        {
            for(int j=0;j<m;j++)
            {
                if(mp[i][j]=='@')               //找起点
                {
                    x=i;
                    y=j;
                }
            }
        }
        int ans=bfs(x,y);
        printf("%d\n",ans);
    }
return 0;
}


【C题】
有n层电梯,每个电梯可以走的【i+k[i]】层,求出从起点走到终点的最少步数。

也是BFS,以步数分成,求出走一步,走两步.........能够走到的地方。

数据范围是[1,200];

那么就遍历这200个点,求出从起点到每个点的最少步数。

#include<stdio.h>
#include<queue>
#include<string.h>
using namespace std;
int n,a,b;
int k[300];
int use[300];
struct node
{
    int x;                              //走到点的坐标
    int step;                           //走到那个点需要的最短步数
};
int check(int x)                       //判断边界  比如走到201 那么就肯定是不可能的
{
    if(x>=1&&x<=n)
        return 1;
    return 0;
}
int bfs()
{
    queue<node>qu;
    memset(use,0,sizeof(use));        //标记第一次走到
    node now,next;
    now.x=a;
    now.step=0;
    use[a]=1; 
    qu.push(now);                    //起点入队列
    while(!qu.empty())
    {
        now=qu.front();
        qu.pop();
        if(now.x==b)                 //如果走到了这个点,就直接返回步数就行了
            return now.step;
        int dx;
        dx=now.x+k[now.x];           //按照第一种方式走
        if(check(dx)==1&&use[dx]==0) //如果没有走过并且满足边界
        {
            use[dx]=1;
            next.x=dx;
            next.step=now.step+1;
            qu.push(next);
        }

        dx=now.x-k[now.x];           //按照第二种方式走
        if(check(dx)==1&&use[dx]==0)
        {
            use[dx]=1;
            next.x=dx;
            next.step=now.step+1;
            qu.push(next);
        }
    }
    return -1;                      //如果所有的遍历都走不到终点,就输出-1
}
int main()
{
    while(scanf("%d",&n),n)
    {
        scanf("%d%d",&a,&b);
        for(int i=1;i<=n;i++)
            scanf("%d",&k[i]);
        int ans=bfs();
        printf("%d\n",ans);
    }
return 0;
}

【D题】

按照象棋中马的走法,求出从起点走到终点的最少步数。

也是BFS,但是跟前面的题不一样在于,走的方向是不同的,不是按照上下左右的方向来走,而是象棋马的走法,大家推一下就可以知道方向数组该怎么写了。

标记数组,标记走到这个点第一次走到。


#include<stdio.h>
#include<string.h>
#include<algorithm>
#include<queue>
using namespace std;
char map[10][10];
int dir[8][2]={1,2,1,-2,-1,-2,-1,2,2,1,2,-1,-2,1,-2,-1};   //方向数组,8个方向
int use[10][10];
int s,e,ss,ee;
struct node                                               //点坐标和走到这个点的最少步数
{
    int x;
    int y;
    int step;
};
int BFS()
{
    queue<node>que;
    node now,next;                                      //处理起点
    now.x=s;
    now.y=e;
    now.step=0;
    use[s][e]=1;
    que.push(now);
    while(!que.empty())
    {
        now=que.front();
        que.pop();

        if(now.x==ss&&now.y==ee)                       //是否走到终点
            return now.step;
        for(int i=0;i<8;i++)                           //8个方向走
        {
            int dx=now.x+dir[i][0];
            int dy=now.y+dir[i][1];
            if(dx>=1&&dx<=8&&dy>=1&&dy<=8&&use[dx][dy]==0)   //第一次走到且在边界里面
            {
                use[dx][dy]=1;
                next.x=dx;
                next.y=dy;
                next.step=now.step+1;
                que.push(next);
            }
        }
    }
}
int main()
{
    char s1[5],s2[5];
    while(scanf("%s%s",s1,s2)!=EOF)
    {
        memset(use,0,sizeof(use));                         //初始化标记数组
        s=s1[0]-'a'+1;
        e=s1[1]-'0';

        ss=s2[0]-'a'+1;
        ee=s2[1]-'0';
        int ans=BFS();
        printf("To get from %s to %s takes %d knight moves.\n",s1,s2,ans);
     }
return 0;
}

【E题】
给出起点和终点,判断是否在时间限制以内从起点走到终点。

也是BFS遍历从起点到终点,但是难点在于这个是两层图,可以在第一层和第二层之间来回走动,认真独题,按照规定来走就行了;

#include<string.h>
#include<stdio.h>
#include<queue>
using namespace std;
char mp[2][15][15];                   //存图,因为是两层图,所以是三维数组,mp[0][][]代表第一层的图,mp[1][][]代表第二层的图
int use[2][15][15];                   //标记是否是第一次走的标记数组 跟存图一样是三维的
int n,m,t,flag;
int dir[4][2]={-1,0,0,-1,1,0,0,1};    //方向
struct node
{
    int z;                            //该点的坐标,位于第z层中的(x,y),走到这里花的最短时间是time.
    int x;
    int y;
    int time;
}ans;
queue<node> que;
void BFS()
{

    while(!que.empty())
    {
        node tem=que.front();
        que.pop();
        if(mp[tem.z][tem.x][tem.y]=='P')
        {
            if(tem.time<=t)
            {
                flag=1;
                return ;
            }
        }
        node next;
        for(int i=0;i<4;i++)     //四个方向
        {
            next.z=tem.z;
            next.x=tem.x+dir[i][0];
            next.y=tem.y+dir[i][1];
            next.time=tem.time+1;
            if(next.z==1&&!use[next.z][next.x][next.y]&&next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&mp[next.z][next.x][next.y]=='#'&&next.time<=t)
            {
                   if(mp[0][next.x][next.y]!='#'&&mp[0][next.x][next.y]!='*')   
                   {
                       use[next.z][next.x][next.y]=1;
                       next.z=0;
                       que.push(next);
                   }
            }
             if(next.z==0&&!use[next.z][next.x][next.y]&&next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&mp[next.z][next.x][next.y]=='#'&&next.time<=t)
            {
                   if(mp[1][next.x][next.y]!='#'&&mp[1][next.x][next.y]!='*')
                   {
                       use[next.z][next.x][next.y]=1;
                       next.z=1;
                       que.push(next);
                   }
            }
            if(mp[next.z][next.x][next.y]!='#'&&!use[next.z][next.x][next.y]&&next.x>=0&&next.x<n&&next.y>=0&&next.y<m&&mp[next.z][next.x][next.y]!='*'&&next.time<=t)
            {
                    use[next.z][next.x][next.y]=1;   
                    que.push(next);
            }
        }
    }

}
int main()
{
    int i,j,k,T;
    scanf("%d",&T);
    while(T--)
    {
        flag=0;
        while (!que.empty())
            que.pop();
        memset(use,0,sizeof(use));
        scanf("%d%d%d",&n,&m,&t);
        for(i=0;i<2;i++)
            for(j=0;j<n;j++)
                scanf("%s",mp[i][j]);

        ans.x = 0, ans.y = 0, ans.z = 0, ans.time = 0;
        use[0][0][0]=1;
        que.push(ans);
        BFS();
        if(flag)
            printf("YES\n");
        else
            printf("NO\n");
    }
return 0;
}



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值