最少步数(bfs)

【题目描述】
在各种棋中,棋子的走法总是一定的,如中国象棋中马走“日”。有一位小学生就想如果马能有两种走法将增加其趣味性,因此,他规定马既能按“日”走,也能如象一样走“田”字。他的同桌平时喜欢下围棋,知道这件事后觉得很有趣,就想试一试,在一个(100×100)的围棋盘上任选两点A、B,A点放上黑子,B点放上白子,代表两匹马。棋子可以按“日”字走,也可以按“田”字走,俩人一个走黑马,一个走白马。谁用最少的步数走到左上角坐标为(1,1)的点时,谁获胜。现在他请你帮忙,给你A、B两点的坐标,想知道两个位置到(1,1)点可能的最少步数。

【输入】
A、B两点的坐标。

【输出】
最少步数。

【输入样例】
12 16
18 10
【输出样例】
8
9
题目分析:
作为广搜的初学者,我认为对一个题深入理解很有必要,最好深入到题的每一个细节以及代码实现的每一步处理方式。
而对这个题最后把我困住的是最少步数的求法,都说广搜来求最优解,在这个题上我算是彻底明白了,我选择了用一个数组来储存到达每个点的最少步数。
例如:minx[i][j]就表示从起点到(i,j)的最少步数。
代码:

#include<iostream>
#include<queue>
using namespace std;
int ax,ay,bx,by;
int tu[101][101];//判断有没有到过这个点
int d[12][2]={2,1,2,-1,1,2,1,-2,-2,1,-2,-1,-1,2,-1,-2,2,2,2,-2,-2,2,-2,-2};//十二个方向
int minx[101][101];//到达(i,j)的最少步数
void bfs(int ,int);//搜索函数
void print();//输出函数
int main()
{
    cin>>ax>>ay;
    cin>>bx>>by;
    tu[ax][ay]=1;//把起点赋值表示到过
    bfs(ax,ay);
    for(int i=1;i<=100;i++)
        for(int j=1;j<=100;j++)
        tu[i][j]=0;
    for(int i=1;i<=100;i++)
        for(int j=1;j<=100;j++)
        minx[i][j]=0;
    tu[bx][by]=1;
    bfs(bx,by);
    return 0;
}
void print()
{
    cout<<minx[1][1]<<endl;
}
void bfs(int x,int y)
{
    queue<int>nx,ny;
    nx.push(x);//起点入队
    ny.push(y);
    while(!nx.empty()&&!ny.empty())//队列非空时执行
    {
        for(int i=0;i<12;i++)//十二个方向
        {
            int xx=nx.front()+d[i][0];//选择跳跃方向
            int yy=ny.front()+d[i][1];
            if(!tu[xx][yy]&&xx>0&&xx<=100&&yy>0&&yy<=100)//判断越界以及是否到过
            {
                nx.push(xx);
                ny.push(yy);
                tu[xx][yy]=1;
                minx[xx][yy]=minx[nx.front()][ny.front()]+1;//最少步数等鱼上一步加一
                if(xx==1&&yy==1)//第一次到达目的地即为最少步数
                {
                    print();return;
                }
            }
        }
        nx.pop();//出队
        ny.pop();
    }
}
输入:
12 16
18 10
输出:
8
9

Process returned 0 (0x0)   execution time : 6.220 s
Press any key to continue.

最后还想说如果真的把这个题弄透的话对于像我一样的初学者来说真的能学到的东西不少!

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这是一个典型的最短路问题,可以使用广度优先搜索(BFS)算法来解决。具体步骤如下: 1. 定义一个二维数组dist,表示每个点到起点的最短步数之和,初始化为无穷大。 2. 定义一个队列queue,将起点加入队列中,并将dist[起点]设为。 3. 对于队列中的每个点,依次考虑其可以到达的下一个点(即马可以走到的8个方向),如果该点未被访问过,则将其加入队列中,并更新dist[该点]为dist[当前点]+1。 4. 重复步骤3,直到队列为空。 5. 最终dist数组中的每个元素即为马从起点到达该点的最少步数之和。 需要注意的是,BFS算法的时间复杂度为O(nm),空间复杂度为O(nm),因此对于较大的棋盘可能会超时或超空间。可以考虑优化算法,比如使用双向BFS或A*算法等。 ### 回答2: 这是一个经典的图论问题,属于最短路算法的一种,我们可以使用BFS(广度优先搜索)来解决这个问题。 首先把所有的点都初始化为无穷大,表示从起点到该点无法到达,同时把起点标记为0,表示从起点到起点的距离为0。 然后从起点开始进行BFS,对于每个访问到的点,计算出其所有未被访问的相邻点到起点的距离,如果小于目前的最短距离,则更新。 这个问题中,我们可以把马看成一个点,然后把其可以到达的点看成相邻点,计算出到这些相邻点的最短距离即可。 具体做法可以使用一个二维数组记录每个点到起点的距离,以及一个队列来存储待访问的点。从起点开始,把其放入队列中,并对其所有相邻点进行更新,同时将其相邻点放入队列中。 然后依次访问队列中的点,并对其相邻点更新距离,直到队列为空。 最终得到的二维数组中,每个点的值即为从起点到该点的最短距离,可以将它们加起来得到答案。 因为题目中给出的n和m并不太大,所以这个算法的时间复杂度可以接受。如果n和m很大,可以考虑使用其他更高效的最短路算法来解决这个问题。 ### 回答3: 这是一个经典的图论问题,可以使用广度优先搜索(BFS)来解决。我们可以将棋盘上每个位置看做是一个节点,它们之间的相对位置则看做边。马在某个位置上,我们可以从它所在的位置开始进行BFS,每次扩展将当前节点可以到达的所有节点加入队列,并标记它们到起始节点的距离。 我们可以使用一个二维数组d来记录每个节点到起始节点的最短距离,初始时将其全部初始化为INF(正无穷大)。BFS过程中,我们从起始节点开始,将其距离设为0,并将其加入队列。然后依次取出队列中的节点,遍历当前节点能够到达的所有节点,并判断是否已经访问过。如果当前节点到该节点的距离加上起始节点到当前节点的距离小于d中该节点的值,就更新该节点的值,并将该节点加入队列。 判断一个节点是否可达可以通过判断其行列坐标之和和之差的绝对值是否为3来实现。 最后,将d数组所有值的和即为答案,表示马从起点到达所有点的最少步数之和。 该算法的时间复杂度为O(nm),空间复杂度为O(nm)。如果需要略微优化空间复杂度,可以使用一个队列来记录已经访问的节点,不再需要使用一个二维数组。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值