饥饿的小易

问题描述

http://www.nowcoder.com/test/question/done?tid=4107357&qid=45843#summary

小易总是感觉饥饿,所以作为章鱼的小易经常出去寻找贝壳吃。最开始小易在一个初始位置x_0。对于小易所处的当前位置x,他只能通过神秘的力量移动到 4 * x + 3或者8 * x + 7。因为使用神秘力量要耗费太多体力,所以它只能使用神秘力量最多100,000次。贝壳总生长在能被1,000,000,007整除的位置(比如:位置0,位置1,000,000,007,位置2,000,000,014等)。小易需要你帮忙计算最少需要使用多少次神秘力量就能吃到贝壳。

笔记

参考了牛客网大神的解答,代码部分是参考大神的代码写的。

题目故意把数字设置的那么大,因此类型要用long long才行。

使用了一个队列q来保存从x_0开始访问过的节点,使用一个map来记录访问这个节点所需的次数。因此是广度优先遍历。

这里还用到了取模的运算规则。

这里是用到的是
如果a%c=a,那么
(a*x+b)%c = (a*(x%c)+b)%c
这个公式说明了,对一个数x,先做a*x+b然后再取模,等于先对x取模,然后做(a*(x%c)+b),最后再取模。

这个有什么用呢?由于题目中给出的数字很大,如果一直做a*x+b的递推,有可能会超过计算机所能表达的数字,但是如果有这个规律,每次都使用取模后的结果做递推,然后再取模,那么递推的结果永远都不会超过模的大小。

具体的证明过程请看:

神奇的取模

代码

#include <iostream>
#include <queue>
#include <map>
using namespace std;

typedef long long llint;
const llint base = 1000000007LL;

int solve(int x0)
{
    queue<int> q;//存储模
    map<int, int> m;//存储{模: 数量}
    q.push(x0);
    m[x0] = 0;
    while (!q.empty())
    {
        llint now = q.front();
        q.pop();
        if (now == 0)
            return m[now];
        if (m[now] > 100000)
            continue;//不计算下一个数了
        int next0 = (now * 4 + 3) % base;
        if (!m[next0])
        {
            m[next0] = m[now] + 1;
            q.push(next0);
        }
        int next1 = (now * 8 + 7) % base;
        if (!m[next1])
        {
            m[next1] = m[now] + 1;
            q.push(next1);
        }
    }
    return -1;
}

int main()
{
    int x0;
    while (cin >> x0)
    {
        cout << solve(x0) << endl;
    }
    return 0;
}
饥饿小易是一个经典的分支限界问题。以下是使用分支限界法求解饥饿小易的步骤: 1. 定义状态:饥饿小易在每个时间点都有一定的能量值,我们可以将每个时间点的能量值作为状态。 2. 定义可行解:饥饿小易需要在有限的时间内获得尽可能多的能量,因此我们需要定义一个可行解。可行解可以定义为小易在每个时间点选择向左或向右移动的方向。 3. 定义目标函数:饥饿小易的目标是在有限的时间内获得尽可能多的能量。因此,我们可以将小易获得的总能量作为目标函数。 4. 定义扩展规则:在每个状态下,饥饿小易可以向左或向右移动一步。在扩展状态时,我们需要考虑小易当前的能量值,如果小易的能量值小于等于当前的时间,则小易将会死亡,因此我们需要剪枝。 5. 用优先队列维护状态:我们可以使用一个优先队列来维护每个状态,并且按照目标函数的值对状态进行排序。在每次扩展状态时,我们将新的状态加入优先队列,并按照目标函数的值对状态进行排序。 6. 执行分支限界算法:使用以上步骤,我们可以执行分支限界算法来求解饥饿小易问题。在每次从优先队列中取出状态时,我们检查当前状态是否为可行解,如果是,则返回当前状态的目标函数值。如果不是,则扩展当前状态,并将新的状态加入优先队列中。 通过以上步骤,我们就可以使用分支限界算法求解饥饿小易问题。
评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值