牛客网 106 J-Various Tree (BFS复习)

题目链接

题目

题目描述
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:

  1. y=x+1

  2. y=x-1

  3. y=x+f(x)

  4. 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 和终点B,每次可以对 A 进行四种操作

  • A=A+1

    • A=A1
    • A=A+f(A)
    • A=Af(A)
    • AB 需要的最少操作次数
      【思路】
      每种状态都有四个可以转移的方向,而且由于小的数可能有更多的1,向前搜索也是有必要的,所以四个搜索的方向都要考虑。

      不妨放在图上思考:含 n 个点,4n条边的有向图,求从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);
      }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值