把博客园图标替换成自己的图标
把博客园图标替换成自己的图标end

OpenJudge 2.5-2971 Catch That Cow(抓住那头牛)

Description

农夫知道一头牛的位置,想要抓住它。农夫和牛都位于数轴上,农夫起始位于点N(0<=N<=100000),牛位于点K(0<=K<=100000)。农夫有两种移动方式:

1、从X移动到X-1或X+1,每次移动花费一分钟

2、从X移动到2*X,每次移动花费一分钟

假设牛没有意识到农夫的行动,站在原地不动。农夫最少要花多少时间才能抓住牛?



Input

两个整数,N和K

Output

一个整数,农夫抓到牛所要花费的最小分钟数

Sample Input
5 17
Sample Output
4

这是我做广搜的第一道题,虽然搜索都学完了 ,我们来看一看广搜应该怎么写吧

广搜要运用到队列的思想,这里我是用的数组来模拟队列,当然用队列做就更不成问题了。

这道题要是用深搜写,很有可能像个无底洞一样,一直都搜不到。别废话了,要是用深搜做广搜题,百分之一百的TLE。所以与深搜不同,广搜优先拓展“宽度”,打个不是很恰当的比方,深搜就是考一门科目,拿100分,广搜就是考八门科目,考60分。

我们先来画个图

(图渣求放过)

我们先来分析一下这幅图(好吧我知道这渣图你们可能什么都看不出来,但看在我辛辛苦苦画的份上就暂且一看),广搜就是不停地拓展树的宽度,先访问完同一层的结点之后再访问下一层。针对这道题而言呢,农夫有三种前进的方式,每一种可以产生一个结点,直至出现了目标结点之后,目标结点的层数就是农夫所走的步数。过程中要标记已经访问过的结点,不再拓展,因为前面已经拓展过这个结点了,再拓展即使得到了解也不是最优解了。

程序我们仍然可以按照框架来写,广搜已经写过框架了,这里就不再赘述,代码奉上(含注释):

#include<cstdio>
#include<cstdio>
int que[1000000],pre[1000000],n,k,next;//que队列,pre前驱
bool mark[1000000];//标记访问过的结点
void print(int x)//根据前驱找父亲结点,计算步数
{
	int sum=0;
	while(pre[x])
	{
		sum++;
		x=pre[x];
	}
	printf("%d",sum);
}
void bfs()
{
	if(n==k) {printf("0"); return;}//坑点,如果农夫一开始就在奶牛的位置,输出0
	int head=0,tail=1;//队列初始化
	que[1]=n;//队头入队,并标记
	mark[n]=1;
	while(head!=tail)
	{
		head++;//队列中的下一个元素作为父结点拓展子结点
		for(int i=1;i<=3;i++)//拓展子结点
		{
			if(i==1) next=que[head]+1;
			if(i==2) next=que[head]-1;	
			if(i==3) next=que[head]*2;//三种前行方式
				if(next<=1000000&&next>=0&&!mark[next])//next<=1000000是为了避免陷入死循环而根据数据范围设定的
			{//next>0为了防止出现负数,负数不能作为数组下标,否则会RE,且mark没有被标记过
				tail++;//队尾指针加1,标记入队
				que[tail]=next;
				mark[next]=1;
				pre[tail]=head;
				if(next==k) //找到目标结点
				{
					print(tail);
					head=tail;//强制退出while
					break;//退出for
				}
			}
		}
	}
}
int main()
{
	scanf("%d %d",&n,&k);
	bfs();
}

最后再说明一下,这里计算步数的时候相当于是找出了所有路径,但是这里只要求所走步数,可以直接用pre[tail]=head+1;就可以了

posted @ 2017-07-04 18:01  Starlight_Glimmer  阅读(27)  评论(0编辑  收藏  举报  来源
浏览器标题切换
浏览器标题切换end