<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">题意:</span>
一个人在一维坐标上抓牛,给定人和牛的坐标,人的移动只有三种:X+1,X-1,X*2,求人抓到牛的最小步数。
思路:
用队列记录状态转移。
感悟:
这是第二次做这题,这次自己做就遇到两个问题:1、会爆内存,因为没有记录,搜过的坐标会再搜一次。2、在剪枝过程中把有可能的情况给剪掉了。
第一次做的时候看别人用step数组记录,原来不仅仅有记录步数的作用,还有记忆化搜索的作用,有点DP的味道。
代码:
1、step数组记录步数同时记忆化搜索:
#include<iostream>
#include<cstdio>
#include<cstring>
#include<queue>
using namespace std;
const int maxn=100000+5;
int step[maxn*2];//step数组记录步数同时记忆化搜索
int main () {
int n,k;
while(cin>>n>>k) {
queue<int> que;
que.push(n);
memset(step,-1,sizeof(step));
step[n]=0;
int temp;
while(!que.empty()) {
temp=que.front();
que.pop();
if(temp == k) {
break;
}
if(temp>0 && step[temp-1]==-1) {
que.push(temp-1);
step[temp-1] =step[temp]+1;
}
if(temp<k && step[temp+1]==-1) {
que.push(temp+1);
step[temp+1] = step[temp]+1;
}
if(temp<k && temp!=0 && step[temp*2]==-1) {
que.push(temp*2);
step[temp*2] = step[temp]+1;
}
}
cout<<step[temp]<<endl;
}
return 0;
}
2、用vis数组记忆化搜索,在队列中插入-1来记录步数
#include<iostream>
#include<cmath>
#include<cstdio>
#include<cstring>
#include<queue>
#include<algorithm>
using namespace std;
bool vis[200000+5];//会爆内存!要记录一下
int main () {
int n,k;
while(cin>>n>>k) {
queue<int> que;
que.push(n);
que.push(-1);
int temp,ans=0;
int maxs=0;
memset(vis,false,sizeof(vis));
while(!que.empty()) {
//maxs=max(maxs,(int)que.size());
int temp = que.front();
que.pop();
if(temp == k)
break;
if(temp==-1) {
ans++;
que.push(-1);
continue;
}
if(!vis[temp]) {
vis[temp]=true;
//错在这个地方!原来条件是temp*2>k,这样有些情况就会被忽略
if(temp>0) {
que.push(temp-1);
}
if(temp<k && temp!=0)
que.push(temp*2);
if(temp<k)
que.push(temp+1);
}
}
cout<<ans<<endl;
}
return 0;
}