题意:
有两个数n和k,有三种操作:+1 、-1、*2,问从数字n到k 最少需要多少步!
由于是求最少步,所有用bfs来搜索。
题解:
这是道简单题,但是容易出现小问题,导致不容易AC。
首先,通过标记数组vis[i ],可以确保每个数只访问一次,同时vis[i]可以用来记录步数。
经过一次变换后的数字 nxt,范围是[0 , MaxN];
这里的数据范围是0-100000;
第一次AC的代码:32ms,写得太丑了
#include<cstdio>
#include<cstring>
#include <iostream>
#include<algorithm>
#include<queue>
using namespace std;
typedef struct Node{
int indx,dis;
}Node;
int f[300005];
int ok;
int main(int argc, const char * argv[]) {
int n,k,ans;
while(~scanf("%d%d",&n,&k)){
if(n>=k) {printf("%d\n",n-k);continue;}
memset(f,-1,sizeof(f));
queue<int >Q;
f[n]=0;
ok=0;
ans=-1;
Q.push(n);
while(!Q.empty() && !ok){
int cur,nxt,stp; // stp代表nxt的当前步数
cur=Q.front();
stp=f[cur]+1;
if(cur==k) {ans=f[cur]; ok=1; break; }
//+
nxt=cur+1;
if(nxt<k*2) //不能无限加
if((f[nxt]>=0 && stp<f[nxt]) || f[nxt]<0) //如果当前位置有历史决策,新决策比历史决策要好
{
f[nxt]=stp;
Q.push(nxt);
}
//-
nxt=cur-1;
if(nxt>=n/2) //不能无限减
if((f[nxt]>=0 && stp<f[nxt]) || f[nxt]<0) //如果当前位置有历史决策,新决策比历史决策要好
{
f[nxt]=stp;
Q.push(nxt);
}
//*2
nxt=cur*2;
if(nxt<k*2) //不能无限乘
if((f[nxt]>=0 && stp<f[nxt]) || f[nxt]<0) //如果当前位置有历史决策,新决策比历史决策要好
{
f[nxt]=stp;
Q.push(nxt);
}
Q.pop();
}
//if(ok)
printf("%d\n",ans);
//else while(1);
}
return 0;
}
第二次AC的代码: 0ms
#include<cstdio>
#include<cstring>
#include <iostream>
#include<algorithm>
#include<queue>
using namespace std;
int vis[100005];
int bfs(int n,int k){
int ret=-1;
memset(vis,-1,sizeof(vis));
vis[n]=0;
queue<int >Q;
Q.push(n);
while(!Q.empty()){
int cur,nxt;
cur=Q.front();
if(cur==k) {ret=vis[cur];break;}
for(int i=0;i<3;i++){
if(i==0) nxt=cur+1;
if(i==1) nxt=cur-1;
if(i==2) nxt=cur*2;
if(nxt<0 || nxt>100005 || vis[nxt]>=0) continue;
vis[nxt]=vis[cur]+1;
Q.push(nxt);
}
Q.pop();
}
return ret;
}
int main(){
int n,k;
while(~scanf("%d%d",&n,&k)){
if(n>=k) {
printf("%d\n",n-k);
continue;
}
printf("%d\n",bfs(n,k));
}
return 0;
}