近期刷题感悟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
- 1≤X≤10e18
- 1≤Y≤10e18
- 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 X - 1 or X + 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
Output
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;
}

浙公网安备 33010602011771号