本学期选了学校的算法课程,P大研究生的算法课程难度不小(PS:对于我这种菜狗),加上本科没有学过算法,更是有点被虐的感觉,所以平时更要多加练习。
没事的时候就去做题。
POJ3278
,2总时间限制: 2000ms 内存限制: 65536kB
- 描述
农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:
1、从X移动到X-1或X+1,每次移动花费一分钟
2、从X移动到2*X,每次移动花费一分钟
假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?- 输入
- 两个整数,N和K
- 输出
- 一个整数,农夫抓到牛所要花费的最小分钟数
- 样例输入
- 5 17
- 样例输出
- 4
- 思路:
- 这个是典型的广搜问题,因为要求的是最短的路径,类似的有迷宫问题找路之类的,广搜一般要用一个结构体(对象)来代表每一个状态,用一个队列queue来记录先后的访问顺序,并且一定要注意状态的边界条件和状态的转换关系(本期中是位置变化的转换关系),农夫可以向前找(+1 表示),也可以向后找(-1 表示),也是跨距离找(* 2表示)
- 注意的地方是 1,广搜的时候每次访问完队头的节点后要把它pop出去。
2, DFS 和BFS 一般实现时都要用一个大的visited 数组表示是否已经访问过了。 - 3, 多种情形扩展时,不能用 else if 而是用并列的 if (DFS也一样),否则搜索空间会减小,一些状态不会被枚举到,else if 直接跳过剩下的cases,一些点就没有入队。 这是一个隐藏的坑。
#include <iostream>
#include <cstring>
#include <queue>
using namespace std;
const int MAXN = 100000;
int visited[MAXN+10]; //判重标记,visited[i] = true表示i已经扩展过
int N,K;
struct step1{
int x;
int steps;
step1(int xx,int ss):x(xx),steps(ss){
}
};
queue<step1> q;
/*
注意的地方是 广搜的时候每次访问完队头的节点后要把它pop出去。
多种情形扩展时,不能用if else 而是用并列的 if (DFS也一样),否则搜索空间会减小。
*/
int main(){
cin>>N>>K;
memset(visited,0,sizeof(visited));
q.push(step1(N,0));
visited[N]=1;
while(!q.empty()){
step1 curS = q.front();
if(curS.x==K){
cout<<curS.steps<<endl;
return 0;
}
if(curS.x-1>=0&& !visited[curS.x-1]){
q.push(step1(curS.x-1,curS.steps+1));
visited[curS.x -1] = 1;
} if(curS.x+1<=MAXN && !visited[curS.x+1]){
q.push(step1(curS.x+1,curS.steps+1));
visited[curS.x +1] = 1;
} if(curS.x*2<=MAXN && !visited[curS.x*2]){
q.push(step1(curS.x*2,curS.steps+1));
visited[curS.x *2] = 1;
}
q.pop(); //每次出队一个结点
}
}
希望坚持下去!!!每天3题!!!