题目描述
牛牛在位置s,牛妹在位置t,初始时op=1,step=1,牛牛每次可以执行以下操作之一:
1.跳:牛牛从当前所在位置x跳到x=x+op*step,随后op=op∗−1,step=step∗2
2.重置:令op=1,step=1
求当牛牛的策略足够优秀时,从s走到牛妹身边t所需要执行的最少操作次数。
1≤s,t≤20000
输入描述
第一行两个整数s,t。
输出描述
输出一行一个整数表示答案。
示例1:
输入
1 5
输出
5
说明
第一步执行”跳“,此时牛牛走到2这个位置。第二步执行”跳”,此时牛牛走到0这个位置。第三步执行“跳”,此时牛牛走到4这个位置。第四步执行“重置”。第五步执行“跳”操作,走到5这个位置。
示例2:
输入
555 666
输出
31
解析
连续使用“跳”,得到的距离是可以知道的,比如跳一次是1,两次是-1,三次是3……
把每一个位置定义为一个节点,而从这个节点连续使用“跳”能达到的节点定义为与之直接相连的节点,它们之间的权值为操作次数,则整个问题转化为单源最短路径,使用dijkstra算法。由于节点有负,记录到每个节点的最短路程是由数组记录的,因此加上一个常数使所有节点映射到正区间。
代码
#include<bits/stdc++.h>
using namespace std;
const int c = 65536;
int main()
{
int s, t;
cin >> s >> t;
int step = 1;
int dis[18] = { 0 };
for (int i = 1; i <= 17; ++i) {
dis[i] = dis[i - 1] + step;
step *= -2;
}
int visited[2 * c + 1] = { 0 };
vector<int> len(2 * c + 1, INT_MAX);
auto cmp = [&](const int& u, const int& v) {
return len[u + c] > len[v + c];
};
priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);
pq.push(s);
len[s + c] = 0;
while (!pq.empty()) {
auto now = pq.top();
pq.pop();
visited[now + c] = 1;
if (now == t) {
break;
}
for (int i = 1; i <= 17; ++i) {
int next = dis[i] + now;
if (abs(next) > c) continue;
if (len[now + c] + i + 1 < len[next + c]) {
len[next + c] = len[now + c] + i + 1;
pq.push(next);
}
}
}
cout << len[t + c] - 1 << endl;
return 0;
}
题目来源
https://ac.nowcoder.com/acm/contest/12949/E
参考代码
https://ac.nowcoder.com/acm/contest/view-submission?submissionId=47580043.房东de狗