【信息学奥赛】鸡飞狗不跳

该文章描述了一个数学问题,鸡从点N出发,通过走一步或飞到当前位置的2倍处去找在点M的狗。问题在于计算鸡达到狗的位置所需的最短时间。文章使用广度优先搜索(BFS)策略,通过队列存储不同位置和对应步数,逐步探索所有可能的路径,最终找到最短时间。给定输入例子中,当鸡在5,狗在17时,鸡最快能在4步内到达狗的位置。
摘要由CSDN通过智能技术生成

题目描述

【题目描述】
有一只鸡和一条狗,他们在一条线上,鸡的位置在点N处,狗在点M处,鸡和狗约定,狗站
那不动,鸡去找狗。可以一次向左或向右走一步,也可一次飞到原来所在位置的2倍处。鸡
飞一次和走一步时间相同。为了不让狗等得着急,鸡最快多长时间能到狗的位置。
【输入描述】
多组测试数据,每组一行N,M(0<=N,M<=100000).
【输出描述】
输出鸡到狗位置的最短时间.
【用例输入】
5 17
【用例输出】 
4

问题分析

 - 我们用一维坐标来表示鸡和狗的位置
 - 按照用例鸡在5这个点,狗在17这个点
 - 那么飞一次就能到的点为4,6,10
 - 飞两次就能到的点为3,8,7,12,9,11,20
 - 飞三次就能到的点为2,16,14,13,24,18,22,19,21,40
 - 飞四次就能到的点为1,15,17,32,28,26,23,25,48,36,22,38,42,39,41,80
 - 那么飞到17这个点只需要4次

在这里插入图片描述

123456789101112131415161718
432101222122334343

设计分析

 - 设计思想我们采用 入队 的方式
 - 开始我们把鸡所在的点5放入队列,并记录飞行时间为0
 - 取出队列中的第一个点,并判断是否到达狗的位置,
 - 如果到达了,返回飞行时间,如果没有到达,那么飞行一次(往前一步、往后一步或两倍处)
 - 飞一次所到达的点4,6,10,并记录飞行的时间为1,依次把这些点放入队列
 - 飞两次所到达的点3,8,7,12,9,11,20,并记录飞行的时间为2,依次把这些点放入队列
 - 飞三次所到达的点2,16,14,13,24,18,22,19,21,40,并记录飞行的时间为3,依次把这些点放入队列
 - 飞四次所到达的点1,15,17,32,28,26,23,25,48,36,22,38,42,39,41,80,
 - 并记录飞行的时间为4,依次把这些点放入队列
 - 此时已经 到达 狗的位置

参考代码

#include <bits/stdc++.h>

using namespace std;

struct Node {
    int x;// 表示在直线上的坐标
    int s;// 表示飞行的次数,也是时间
};
int vis[100010];
// 记录直线上的点是否飞过,飞过记为1,没有飞过记为0

int n, m;// n表示鸡的位置,m表示狗的位置


// 广度优先搜索
int bfs() {
    queue<Node> q;// 定义一个队列
    Node root;// 所放的节点
    root.x = n;// 鸡刚开始的位置
    root.s = 0;// 飞行时间为0
    q.push(root);// 放入队列
    vis[n] = 1;// n这个点被访问过了

    while (!q.empty()) {
        Node p = q.front();// 取第一个元素(鸡的位置)
        q.pop();// 删除第一个元素
        if (p.x == m) {// 鸡的位置,是否等于狗的位置(终止条件)
            return p.s;// 返回飞行的次数(时间)
        }
        // 三种情况
        int tx = p.x + 1;// 向右飞一步
        if (tx >= 0 && tx <= 100000 && !vis[tx]) {
            Node su;
            su.x = tx;
            su.s = p.s + 1;// 次数加一
            q.push(su);// 重新放入队列
            vis[tx] = 1;// 标记点已经走过
        }
        tx = p.x - 1;// 向左飞一步
        if (tx >= 0 && tx <= 100000 && !vis[tx]) {
            Node su;
            su.x = tx;
            su.s = p.s + 1;
            q.push(su);
            vis[tx] = 1;
        }
        tx = 2 * p.x;// 飞到两倍之处
        if (tx >= 0 && tx <= 100000 && !vis[tx]) {
            Node su;
            su.x = tx;
            su.s = p.s + 1;
            q.push(su);
            vis[tx] = 1;
        }
    }

}

int main() {
    // 多组数据
    while (cin >> n >> m) {
        memset(vis, 0, sizeof(vis));// 初始化
        cout << bfs() << "\n";
    }
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值