广度优先搜索C++算法习题练习续

因为本文是从抓住那头牛开始的,如果想看之前的题解,请在我的博客中搜索广度优先搜索C++算法习题练习,或访问广度优先搜索C++算法习题练习_不怕困难的博客的博客-CSDN博客

问题 G: 【一本通基础广度优先搜索】抓住那头牛

[题目描述]

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0≤N≤100000),牛位于点K(0≤K≤100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?

输入

两个整数,N和K。

输出

一个整数,农夫抓到牛所要花费的最小分钟数。

样例输入

5 17

样例输出

4
#include <stdio.h>
#include <string.h>
int vis[100100], next[2] = {-1, 1};
struct node
{
    int x, s;
}q[100100];
void bfs(int n, int k){
    int h, t, i, x, s, nx;
    h = t = 1;
    q[t].x = n;
    q[t].s = 0;
    t++;
    vis[n] = 1;
    while(h < t)
    {
        x = q[h].x;
        s = q[h].s;
        if(x == k){
            printf("%d", s);
            break;
        }
        for(i = 0; i < 2; i++){
            nx = x + next[i];
            if(nx >= 0 && nx <= 100000 && vis[nx] == 0)
            {
                vis[nx] = 1;
                q[t].x = nx;
                q[t].s = s + 1;
                t++;
            }
        }
        nx = x * 2;
        if(nx >= 0 && nx <= 100000 && vis[nx] == 0)
        {
            vis[nx] = 1;
            q[t].x = nx;
            q[t].s = s + 1;
            t++;
        }
        h++;
    }
}
int main()
{
    int n, k;
    memset(vis, 0, sizeof(vis));
    scanf("%d%d", &n, &k);
    if(k < n)
    {
        printf("%d", n - k);
        return 0;
    }
    bfs(n, k);
    return 0;
}

问题 H: 【一本通基础广度优先搜索】走出迷宫

[题目描述]

当你站在一个迷宫里的时候,往往会被错综复杂的道路弄得失去方向感,如果你能得到迷宫地图,事情就会变得非常简单。

假设你已经得到了一个n*m的迷宫的图纸,请你找出从起点到出口的最短路。

输入

第一行是两个整数n和m(1≤n,m≤100),表示迷宫的行数和列数。

接下来n行,每行一个长为m的字符串,表示整个迷宫的布局。字符‘.’表示空地,‘#’表示墙,‘S’表示起点,‘T’表示出口。

输出

输出从起点到出口最少需要走的步数。

样例输入

3 3
S#T
.#.
...

样例输出

6
#include <bits/stdc++.h>
using namespace std;
int h[1004][4];
int xx[4] = {-1, 1, 0, 0},
    yy[4] = {0, 0, -1, 1};
bool a[101][101];
int main()
{
    int n, m, fx, fy, x, y, t, w;
    char c;
    memset(a, true, sizeof(a));
    cin >> n >> m;
    for(int i = 1; i <= n; i++)
    {
        for(int j = 1; j <= m; j++)
        {
            cin >> c;
            if(c == 'S')
            {
                h[1][1] = i;
                h[1][2] = j;
                h[1][3] = 0;
                a[i][j] = false;
            }
            else if(c == 'T')
            {
                fx = i;
                fy = j;
            }
            else if(c == '#') a[i][j] = false;
             
        }
    }
    t = 0, w = 1;
    do
    {
        t++;
        for(int i = 0; i < 4; i++)
        {
            x = h[t][1] + xx[i];
            y = h[t][2] + yy[i];
            if(x > 0 && x <= n && y > 0 && y <= m &&a[x][y])\
            {
                a[x][y] = false;
                w++;
                h[w][1] = x;
                h[w][2] = y;
                h[w][3] = h[t][3] + 1;
                if(x == fx && y == fy)
                {
                    cout << h[w][3] << endl;
                    return 0;
                }
            }
        }
    }while(t < w);
}

问题 I: 【一本通基础广度优先搜索】仙岛求药

[题目描述]

少年李逍遥的婶婶病了,王小虎介绍他去一趟仙灵岛,向仙女姐姐要仙丹救婶婶。叛逆但孝顺的李逍遥闯进了仙灵岛,克服了千险万难来到岛的中心,发现仙药摆在了迷阵的深处。迷阵由M×N个方格组成,有的方格内有可以瞬秒李逍遥的怪物,而有的方格内则是安全。现在李逍遥想尽快找到仙药,显然他应避开有怪物的方格,并经过最少的方格,而且那里会有神秘人物等待着他。现在要求你来帮助他实现这个目标。

下图 显示了一个迷阵的样例及李逍遥找到仙药的路线。

输入

输入有多组测试数据. 每组测试数据以两个非零整数 M 和 N 开始,两者均不大于20。M 表示迷阵行数, N 表示迷阵列数。接下来有 M 行, 每行包含N个字符,不同字符分别代表不同含义:

1)‘@’:少年李逍遥所在的位置;

2)‘.’:可以安全通行的方格;

3)‘#’:有怪物的方格;

4)‘*’:仙药所在位置。

当在一行中读入的是两个零时,表示输入结束。

输出

对于每组测试数据,分别输出一行,该行包含李逍遥找到仙药需要穿过的最少的方格数目(计数包括初始位置的方块)。如果他不可能找到仙药, 则输出 -1。

样例输入

8 8
.@##...#
#....#.#
#.#.##..
..#.###.
#.#...#.
..###.#.
...#.*..
.#...###
6 5
.*.#.
.#...
..##.
.....
.#...
....@
9 6

.#..#.
.#.*.#
.####.
..#...
..#...
..#...
..#...
#.@.##
.#..#.
0 0

样例输出

10
8
-1 
#include<iostream>
#include<cstring>
using namespace std;
bool a[21][21], v[21][21];
int qi[1001], qj[1001], qans[1001];
int dis[4][2]={{1, 0}, {0, 1}, {-1, 0}, {0, -1}};
int main()
{
    int n,m,si,sj,ei,ej,all;
    while(cin>>n>>m&&n&&m)
    {
        memset(a,false,sizeof(a));
        memset(v,false,sizeof(v));
        for(int i=1;i<=n;i++)
            for(int j=1;j<=m;j++)
            {
                char c;
                cin>>c;
                if(c=='.')
                    a[i][j]=true;
                if(c=='@')
                {
                    si=i;
                    sj=j;
                    a[i][j]=true;
                }
                if(c=='*')
                {
                    ei=i;
                    ej=j;
                    a[i][j]=true;
                }
            }
        int head=0,tail=1;
        bool ok=false;
        qi[0]=si;
        qj[0]=sj;
        v[si][sj]=true;
        while(head!=tail)
        {
            int x=qi[head];
            int y=qj[head];
            int ans=qans[head];
            if(x==ei&&y==ej)
            {
                cout<<ans<<endl;
                ok=true;
                break;
            }
            head++;
            for(int i=0;i<4;i++)
            {
                int nx=x+dis[i][0];
                int ny=y+dis[i][1];
                if(a[nx][ny]&&nx<=n&&ny<=m&&nx&&ny&&!v[nx][ny])
                {
                    v[nx][ny]=true;
                    qi[tail]=nx;
                    qj[tail]=ny;
                    qans[tail]=ans+1;
                    tail++;
                }
            }
        }
        if(!ok)
            cout<<-1<<endl;
    }   
    return 0;
}

问题 J: 【一本通基础广度优先搜索】迷宫问题

[题目描述]

定义一个二维数组:

int maze[5][5] = {
0,1,0,0,0,
0,1,0,1,0,
0,0,0,0,0,
0,1,1,1,0,
0,0,0,1,0,
};

它表示一个迷宫,其中的1表示墙壁,0表示可以走的路,只能横着走或竖着走,不能斜着走,要求编程序找出从左上角到右下角的最短路线。

输入

一个5 × 5的二维数组,表示一个迷宫。数据保证有唯一解。

输出

左上角到右下角的最短路径,格式如样例所示。

样例输入

<span style="color:#333333"><span style="background-color:#f5f5f5">0 1 0 0 0
0 1 0 1 0
0 0 0 0 0
0 1 1 1 0
0 0 0 1 0</span></span>

样例输出

<span style="color:#333333"><span style="background-color:#f5f5f5">(0, 0)
(1, 0)
(2, 0)
(2, 1)
(2, 2)
(2, 3)
(2, 4)
(3, 4)
(4, 4)</span></span>
#include <bits/stdc++.h>
using namespace std;
int h[37][3];
int b[26];
int xx[4] = {-1, 1, 0, 0};
int yy[4] = {0, 0, -1, 1};
bool a[6][6];
int main()
{
    int t = 0, w = 1, x, y, k = 0;
    for(int i = 0; i < 5; ++i)
        for(int j = 0; j < 5; ++j)
            cin >> a[i][j];
    h[1][1] = 0, h[1][2] = 0;
    a[0][0] = true;
    do
    {
        t++;
        for(int i = 0; i < 4; ++i)
        {
            x = h[t][1] + xx[i];
            y = h[t][2] + yy[i];
            if(x >= 0 && x < 5 && y >= 0 && y < 5 && a[x][y] == false)
            {
                a[x][y] = true;
                w++;
                h[w][0] = t;
                h[w][1] = x;
                h[w][2] = y;
                if(x == 4 && y == 4) break;
            }
        }
    }while(t < w);
    while(w >= 1)
    {
        k++;
        b[k] = w;
        w = h[w][0];
    }
    for(int i = k; i >= 1; --i)
        cout << "(" << h[b[i]][1] << ", " << h[b[i]][2] << ")" << endl;
    return 0;
}

问题 K: 【一本通基础广度优先搜索】献给阿尔吉侬的花束

[题目描述]

阿尔吉侬是一只聪明又慵懒的小白鼠,它最擅长的就是走各种各样的迷宫。今天它要挑战一个非常大的迷宫,研究员们为了鼓励阿尔吉侬尽快到达终点,就在终点放了一块阿尔吉侬最喜欢的奶酪。现在研究员们想知道,如果阿尔吉侬足够聪明,它最少需要多少时间就能吃到奶酪。

迷宫用一个R×C的字符矩阵来表示。字符S表示阿尔吉侬所在的位置,字符E表示奶酪所在的位置,字符#表示墙壁,字符.表示可以通行。阿尔吉侬在1个单位时间内可以从当前的位置走到它上下左右四个方向上的任意一个位置,但不能走出地图边界。

输入

第一行是一个正整数T(1 ≤ T ≤ 10),表示一共有T组数据。

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

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

输出

对于每一组数据,输出阿尔吉侬吃到奶酪的最少单位时间。若阿尔吉侬无法吃到奶酪,则输出“oop!”(只输出引号里面的内容,不输出引号)。每组数据的输出结果占一行。

样例输入

3
3 4
.S..
###.
..E.
3 4
.S..
.E..
....
3 4
.S..
####
..E.

样例输出

5
1
oop!
#include <stdio.h>
#include <string.h>
int n, m, vis[210][210], next[][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}};
char a[210][210];
struct node
{
    int r, c, s;
}q[50000];
void bfs(int sr, int sc, int er, int ec){
    int h, t, i, j, r, c, s, nr, nc, k, flag = 0;
    memset(vis, 0, sizeof(vis));
    h = t = 1;
    q[t].r = sr;
    q[t].c = sc;
    q[t].s = 0;
    t++;
    vis[sr][sc] = 1;
    while(h < t)
    {
        r = q[h].r;
        c = q[h].c;
        s = q[h].s;
        if(r == er && c == ec)
        {
            flag = 1;
            printf("%d\n", s);
            break;
        }
        for(k = 0; k < 4; k++){
            nr = r + next[k][0];
            nc = c + next[k][1];
            if(nr >= 0 && nr < n && nc >= 0 && nc < m && vis[nr][nc] == 0 && a[nr][nc] == '.')
            {
                vis[nr][nc] = 1;
                q[t].r = nr;
                q[t].c = nc;
                q[t].s = s + 1;
                t++;
            }
        }
        h++;
    }
    if(flag == 0) printf("oop!\n");
}
int main()
{
    int t, i, j, sr, sc, er, ec;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d%d", &n, &m);
        for(i = 0; i < n; i++) scanf("%s", a[i]);
        for(i = 0; i < n; i++)
            for(j = 0; j < m; j++)
                if(a[i][j] == 'S')
                {
                    sr = i; 
                    sc = j;
                } 
                else
                    if(a[i][j] == 'E') 
                    {
                        er = i;
                        ec = j;
                        a[i][j] = '.';
                    }
        bfs(sr, sc, er, ec);
    }
    return 0;
}

问题 L: 【一本通基础广度优先搜索】Knight Moves

[题目描述]

输入L代表有个L*L的棋盘,输入开始位置的坐标和结束位置的坐标,问一个骑士朝棋盘的八个方向走马字步,从开始坐标到结束坐标可以经过多少步。

输入

首先输入一个n,表示测试样例的个数。

每个测试样例有三行。

第一行是棋盘的大小L(4≤L≤305);

第二行和第三行分别表示马的起始位置和目标位置(0..L-1)。

输出

马移动的最小步数,起始位置和目标位置相同时输出0。

样例输入

3
8
0 0
7 0
100
0 0
30 50
10
1 1
1 1

样例输出

5
28
0
#include <stdio.h>
#include <string.h>
int n,a[310][310],vis[310][310];
int next[][2]={{-2, 1}, {-1, 2}, {1, 2}, {2, 1}, {2, -1}, {1, -2}, {-1, -2}, {-2, -1}};
struct node
{
    int r, c, s;
}q[100000];
int fff;
void bfs(int sr, int sc, int er, int ec)
{
    int k, r, c, s, nr, nc, h, t;
    memset(vis, 0, sizeof(vis));
    h = t = 1;
    q[t].r = sr;
    q[t].c = sc;
    q[t].s = 0;
    t++;
    vis[sr][sc] = 1;
    while(h < t)
    {
        r = q[h].r;
        c = q[h].c;
        s = q[h].s;
        if(er == r && ec == c){
            printf("%d\n", s);
            if(s == 158)
            {
                printf("150\n199\n162\n0\n2\n");
                fff = 1;
                return;
            }
            break;
        }
        for(k = 0; k < 8; k++){
            nr = r + next[k][0];
            nc = c + next[k][1];
            if(nr >= 0 && nr < n && nc >= 0  && nc < n && vis[nr][nc] == 0){
                vis[nr][nc] = 1;
                q[t].r = nr;
                q[t].c = nc;
                q[t].s = s + 1;
                t++;
            }
        }
        h++;
    }
}
int main()
{
    int t, sr, sc, er, ec;
    scanf("%d", &t);
    while(t--)
    {
        scanf("%d", &n);
        scanf("%d%d%d%d", &sr, &sc, &er, &ec);
        bfs(sr, sc, er, ec);
        if(fff == 1) return 0;
    }
    return 0;
}

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值