题目
题目描述
It’s universally acknowledged that there’re innumerable trees in the campus of HUST.
And there are many different types of trees in HUST, each of which has a number represent its type. The doctors of biology in HUST find 4 different ways to change the tree’s type x into a new type y:
y=x+1
y=x-1
y=x+f(x)
- y=x-f(x)
The function f(x) is defined as the number of 1 in x in binary representation. For example, f(1)=1, f(2)=1, f(3)=2, f(10)=2.
Now the doctors are given a tree of the type A. The doctors want to change its type into B. Because each step will cost a huge amount of money, you need to help them figure out the minimum steps to change the type of the tree into B.
Remember the type number should always be a natural number (0 included).
输入描述:
One line with two integers A and B, the init type and the target type.
输出描述:
You need to print a integer representing the minimum steps.
示例1
输入
5 12
输出
3
说明
The minimum steps they should take: 5->7->10->12. Thus the answer is 3.
分析
【题意】
给出起点
A
和终点
A=A+1 - A=A−1
- A=A+f(A)
- A=A−f(A)
求 A→B 需要的最少操作次数
【思路】
每种状态都有四个可以转移的方向,而且由于小的数可能有更多的1,向前搜索也是有必要的,所以四个搜索的方向都要考虑。不妨放在图上思考:含 n 个点,
4∗n 条边的有向图,求从A出发到B的最短路径。咋一看,往四个方向搜索会产生指数级的新状态,但其实总体来看,一共只有1e6个点,最坏的情况也不过是把所有的点都搜索一遍而已,由于是无权图求最短路径,直接上BFS搜索即可。
【注意】
虽然说最坏的情况要搜索所有的点一遍,但这还是要建立在剪枝的基础上:搜索过的点一定不能重复搜索,不然复杂度会炸(不要问我为什么知道)代码
#include<stdio.h> #include<queue> using std::queue; int a, b; //预处理1~n每个十进制数含有的1的个数 int bo[1000006] = { 0 }; int f(int x) { if (x <= 0)return 0; if (bo[x] > 0)return bo[x]; int temp = x / 2; return bo[x] = (f(temp) + x % 2); } //BFS辅助队列 queue<int> help; int aim; //vis数组记录搜索过的状态,防止在环上反复搜索,把需要搜索的状态总数降低到n个 int vis[1000006] = { 0 }; //bfs的非递归写法 int bfs(int cur,int cost) { int sz; int temp; while (!help.empty()) { sz = help.size(); for (int i = 0; i < sz; ++i) { temp = help.front(); help.pop(); if (vis[temp] == 1)continue; else vis[temp] = 1; //遇到终点,结束搜索 if (temp == aim)return cost; //加入下一次搜索的四个新状态 help.push(temp - 1); help.push(temp + 1); help.push(temp - f(temp)); help.push(temp +f(temp)); } ++cost; } return -1;//没找到,理论上是不可能的(重复+1/-1一定能得到B),但为了语法上的正确添加一个返回值 } int main() { scanf("%d %d", &a, &b); help.push(a); aim = b; b = bfs(a, 0); printf("%d", b); }