noj加1乘2平方

广度优先搜索典例

00 题目

描述:

最简单的队列的使用
 1 #include <iostream>
 2 #include <queue>
 3 using namespace std;
 4 queue<int> q1;
 5 int main()
 6 {
 7     int temp, x;
 8     q1.push(5);//入队
 9     q1.push(8);//入队
10     temp = q1.front();//访问队首元素
11     q1.pop();//出队
12     q1.empty();//判队列是否为空
13     q1.back();//返回队尾元素
14     q1.size();//返回队列长度
15 }
 

给定两个正整数m、n,问只能做加1、乘2和平方这三种变化,从m变化到n最少需要几次

输入:

输入两个10000以内的正整数m和n,且m小于n

输出:

输出从m变化到n的最少次数

输入样例:

1 16

输出样例:

3

01 思路0

01-1 类型

虽然看上去感觉有一些无处下手,但是实际上就是一个三叉树,并且要去去找 到达目标节点 的最低高度。

这个图转自加1乘2平方题解

在这里插入图片描述

很明显,这是个广搜典型题。

01-2 算法

  1. 以初始数字(如1)当作根结点,入队,出队,产生三个子节点next,对子节点筛选符合条件的继续进队

    关于三个子结点的产生,可以设置标志位标记为0,1,2

    • 0->当前值+1

    • 1->当前值*2

    • 2->当前值*当前值

    对应我的change函数

  2. 对next值进行判断

    • 当next为终点数字时,就停止,返回高度(高度需要变量来记)

    • 当next>终点数字时,不再入队。

    • 当next<终点数字时,入队,方便下一步找它的子节点。

  3. 在bfs主控函数中把队列走完,就能解决问题。

  4. 输出

 

02 代码0

 1 //方法2
 2 //按照题目要求使用队列,相应算法是广搜
 3 #include<iostream>
 4 #include<queue>
 5 using namespace std;
 6  7 queue<int> q;
 8 int m,n;
 9 int step[10000];
10 int used[10000];
11 12 int bfs();//广度优先搜索
13 int change(int now, int i);//三种变换
14 bool istarget(int now, int next);
15 //判断是否达到目标数字
16 int main(){
17     cin >> m >> n;
18     //始末位置
19     q.push(m);
20     //m入队
21     cout << bfs() << endl;
22     return 0;
23 }
24 int bfs(){
25     int next;
26     while(!q.empty() ){
27         int now = q.front();
28         q.pop();
29         used[now]=1;
30         for(int i=0; i<3; i++){
31             next = change(now,i);
32             //生成当前节点的下一节点(一共三个)
33             if(istarget(now, next)){
34                 return step[next];
35             }//如果就达到目标,就返回走了几步,由于使用广搜,就是最短路径
36         }
37     }
38     return 0;//这点很重要,虽然code永远到不了这里
39 }
40 41 bool istarget(int now,int next){
42     if(next<=n && used[next]==0){//确保子节点未超过目标值且未被访问过
43         used[next]=1;
44         step[next] = step[now] + 1;//从当前到子节点需+1
45         //核心判断
46         if(next == n){
47             return true;
48         }
49         else{
50             q.push(next);
51             //如果不是就吧这个节点当成普通节点放入队列
52         }
53     }
54     return false;
55 }
56 57 int change(int now, int i){
58     if(i==0) return now+1;
59     if(i==1) return now*2;
60     else return now*now;
61 }

 

03 思路1

03-1 类型

动态规划,更为简洁,只需要一个main函数和两个指针

03-2 算法

  • 从起始数字开始,我设置一个行走位逐个去走到终点

  • 对i进行讨论

    • 先设置基准步伐,比较i的路经长度和i-1的路径长度+1

    • 当i为偶数,比较到达i的路径长度和i/2的路径长度+1

    • 当i为平方数,(可以提前设置一个int 的i的根号,当t*t==i即为这个条件)比较到达i的路径长度和t的路径长度+1

  • 算法原理,因为i是从m开始走的,所以天然不需要循环,只需不断地调用之前的结果进行比较就能得到新的结果,这就是动态规划的魅力所在。算法时间复杂度为O(m-n).

 

04 代码1

 1 //加1乘2平方
 2  3 #include<stdio.h>
 4 #include<string.h>
 5 #include<iostream>
 6 #include<algorithm>
 7 #include<cmath>
 8 using namespace std;
 9 const int maxn = 10000+50;
10 int dp[maxn],m,n;
11 12 //min函数内置了
13 int main(){
14     cin>>m>>n;
15     memset(dp,0x3f3f3f,sizeof(dp));
16     dp[m] = 0;
17     for(int i = m+1; i <= n; i++){
18         int t = sqrt(i);
19         dp[i]=min(dp[i],dp[i-1]+1);
20         if(i%2==0){
21             dp[i] = min(dp[i], dp[i/2]+1);
22         }
23         if(t*t == i){
24             dp[i] = min(dp[i],dp[t]+1);
25         }
26     }
27     cout << dp[n] << endl;
28     return 0;
29 }

 

 

posted @ 2021-10-23 11:41  climerecho  阅读(154)  评论(0编辑  收藏  举报