近期刷题感悟1(搜索)

一个经典算法题

         给你两个数n,m,有加一减一乘2三种操作,问从n到m的最小操作次数是多少?

         首先我们很容易想到这是一个搜索题,dfs和bfs应该是都可以的,但是atcoder 188 F 那道题dfs能过,但是poj  3278 就是不行??? 我真就觉得没啥区别啊,运行错误是为啥,嘤嘤嘤。

Atcoder 188 F - +1-1x2

Problem Statement

Takahashi has written an integer X on a blackboard. He can do the following three kinds of operations any number of times in any order:

  • increase the value written on the blackboard by 1;
  • decrease the value written on the blackboard by 1;
  • multiply the value written on the blackboard by 2.

Find the minimum number of operations required to have YYwritten on the blackboard.

Constraints

  • 1X10e18
  • 1Y10e18
  • XX and YY are integers.

      恕我直言,这题数据范围给的挺反人类的,别杠杠就是我对,正常小白不都习惯用数组存数,谁会用map啊,首先我们可以分情况分析一下,首先,如果x比y大的话,那毫无疑问,就一直减一就行了,之后可以还可以分两种,一种是y是偶数,那么得到y有两种情况,一种是y/2乘二得的,一种是直接一直加一,我们要求最小,那么取一个min就好了,而y要是奇数,显然不可能有一个数直接乘2得到,应该是加一乘2或者减一乘2(反过来也一样),我们把这两种跟一直加一的取一个min,我们可以把dfs过程中算出得一些量存下来,也可以说是记忆化搜索。

#include <iostream>
#include<cstdio>
#include<string>
#include<algorithm>
#include <map>
#include <math.h>
#include <set>
#include<sstream>
using namespace std;
typedef long long ll;
map<ll,ll>dp;   //map映射存数
ll x,y;
ll dfs(ll n)
{
    if(x>=n)  return x-n;
    if(dp[n]) return dp[n];
    ll ans=n-x; //加一操作;
    if(n%2==0)
    {
        ans=min(ans,dfs(n/2)+1);
    } 
    else
    {
        ans=min(dfs((n-1)/2)+2,ans); //减一翻倍 
        ans=min(dfs((n+1)/2)+2,ans);//加一翻倍 
    }
    return dp[n]=ans; 
}
int main()
{
    cin >> x >> y;
    cout << dfs(y); 
    return 0;
}

POJ 3278

Farmer John has been informed of the location of a fugitive cow and wants to catch her immediately. He starts at a point N (0 ≤ N ≤ 100,000) on a number line and the cow is at a point K (0 ≤ K ≤ 100,000) on the same number line. Farmer John has two modes of transportation: walking and teleporting.

* Walking: FJ can move from any point X to the points - 1 or + 1 in a single minute
* Teleporting: FJ can move from any point X to the point 2 × X in a single minute.

If the cow, unaware of its pursuit, does not move at all, how long does it take for Farmer John to retrieve it?

Input

Line 1: Two space-separated integers: N and K

Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

Sample Input

5 17

Sample Output

4

我开始拿来一看,这不跟上面那个差不多嘛,我一交,运行错误,我把map改成正常数组,还是运行错误,dfs难道出现了递归的错误的?出不去?这题网上的正解都是清一色的三入口的bfs,orz

我们来分析一下BFS的思路,显然是三个入口,具体看代码

#include<iostream>
#include<queue>
#include<cstring>
#include<cstdio>
#include <algorithm>
#include <map>
using namespace std;
typedef long long ll;
queue<int> q;
int m,n;
bool vis[100009];
int step[100009];
int rear,front;//rear表示下一步
int BFS()
{
int i;
q.push(n);//把农民的位置压入队列
step[n]=0;//步数记为0
vis[n]=1;//标记这个点走过
while(!q.empty()){//队列不为空哦时执行
front=q.front();//最开始的位置
q.pop();//弹出队列头
for(i=0;i<3;i++)//三种走法,三种循环
{
if(i==0)
rear=front+1;//第一种下一步+1
if(i==1)
rear=front-1;//第二种下一步-1
if(i==2)
rear=front*2;//第三种步数翻倍
if(rear>=0&&rear<=1e18&&vis[rear]==0)//判断是否越界,并且这一步没有走过
{
vis[rear]=1;//标记这一步走过了
step[rear]=step[front]+1;// 步数+1
q.push(rear);//将当前位置压入队列
}
if(rear==m) return step[rear];
}
}return -1;

}

int main(){

cin >> n >> m;
memset(step,0,sizeof(step));//初始化为0
memset(vis,0,sizeof(vis));//初始化为false
cout << BFS();

return 0;
}

 

 

 

 

posted @ 2021-02-12 14:01  报与桃花一处开  阅读(124)  评论(0)    收藏  举报
返回顶端