[POJ - 3278 ]C - Catch That Cow

题目阅读

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?

生词

fugitive [ˈfju:dʒətɪv] adj. 逃亡的

teleporting n.远距离传送

retrieve [rɪˈtriːv] v.找回

名为FJ的人寻找丢失的牛,这头牛并不移动,可以视为从起点到终点的问题。

并且这里的路只是一条单向路,不同于二维、三维的迷宫,而且只用一维的标记数组就可以实现对迷宫的覆盖,但这道题难点并不在迷宫的表示方法上。

移动方向不仅仅是移动一格,这就可以通过对枚举的次数来选择移动方式

for(i=0;i<3;i++)
		{
			if(i==0)tx=temp.x+1;
			else if(i==1)tx=temp.x-1;
			else tx=temp.x*2;
			ts=temp.s+1;

}

而且我们需要考虑越界的问题,题目中合法范围是[0,100000],则非法就是

if(tx<0||tx>100000)continue;

对应标记数组定义为

int book[100010];

Input

Line 1: Two space-separated integers: N and K

Output

Line 1: The least amount of time, in minutes, it takes for Farmer John to catch the fugitive cow.

求最短路,无疑要用到BFS。然而只写BFS却报了错误Wrong Answer。为什么呢?网上的题解无一例外的标注该题为BFS,但我想强调的是出题者的设坑点在于n,k大小关系导致枚举方向的选择不同,也就是需要分类讨论:

当n>k时,人可以选择的方向只有后退;

当n=k时,人不用走;

当n<k时,可以通过题目给出的三种移动方法:前移、后移、传送来寻找最短路。这里的可以前移后移表现为以坐标为节点的有向图的互相连通的边,例如下图中的2、3节点。在这里插入图片描述

而只写BFS导致n>k这种简单问题复杂为尝试南辕北辙这种无意义且浪费时间的情况,而这是导致WA的原因。

怎么改进呢?很明显由于人只能在相邻方块移动,不难想到两两交换的冒泡排序的求交换次数问题,我们并非需要真的交换元素(移动人的位置),而是通过起点终点坐标的差值即可得到移动步数,即n-k。这个式子同样适合n=k,不妨将这两种情况归位一类。

if(n>=k) {
	printf("%d\n",n-k);
	return 0;
	}

类似利用规律而不采用操作模拟的解法,可以参考Stacks of Flapjacks [UVA - 120]。

当然,我们需要用BFS去求解n>k的情况,同样我们只给出注意的点,而不逐一详细解释代码。

1.方向控制

在上文提过解法,不再赘述。

2.不可走

①越界

同样上文给出了解释

②访问过的结点。

它记录的步数一定是最短路径能达到的步数,因为BFS的每层结点都是能到达该节点的最短步数,因而不需要考虑记录并更新到达每个位置步数的最小值(受《啊哈算法》第四章第2节解救小哈 解法的影响)

if(!book[tx])

最后,不妨贴出源码:

#include<iostream>
#include<queue>
#include<cstring>
using namespace std;
int n,k;
int book[100010];
struct node{
	int x,s;
};
int main(){
	freopen("test.txt","r",stdin);
	cin>>n>>k;
	if(n>=k) {
	printf("%d\n",n-k);
	return 0;
	}
    

queue<node> que;
int i,tx,ts,flag=0;;
memset(book,0,sizeof(book));
struct node t,temp;
t.x=n;
t.s=0;
que.push(t);
book[n]=1;
while(!que.empty()){
	temp=que.front();
	for(i=0;i<3;i++)
	{
		if(i==0)tx=temp.x+1;
		else if(i==1)tx=temp.x-1;
		else tx=temp.x*2;
		ts=temp.s+1;
		if(tx<0||tx>100000)continue;
		if(!book[tx])
		{
			t.x=tx;
			t.s=ts;
			book[tx]=1;
			que.push(t);
			if(tx==k){
				cout<<que.back().s;
				return 0;
			}
		}
	}
	que.pop();
}	
return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值