在我写的那篇深信服在线笔试下面看到一个推荐,是提前批的笔试题目,看了一下,选了一个挺有意思的题目来做。(练习练习算法)
做了蛮久才做出来的,从思考这个问题目的,以及其出现的情况,再到编码+调试错误,花了很长时间…思路虽然理清很快,但是在编写的过程中犯了很多小错误。
可以看出目的是让输入的序列能够满足一定条件即输出Yes or No,而我们的目标就是找到一定能够抓到兔子的条件,而一定能够抓到兔子,也就是无论兔子初始在哪个位置,这个序列都能够满足抓到。
而我们要模拟出兔子在各个洞口之间的转移,可以分为以下的情况:
(兔子位置为p,兔子洞数为d,下一天小强检查的洞口为n)
1、p-1<0 || p+1>d
,即墙角不能移动,下次移动只能+1或-1。
2、p+1!=n &&p-1!=n
,这里就产生fork,出现不同的状态(p-1与p+1),所以需要记录下来(可以用递归或者是栈)。
3、p+1==n与p-1==n
,如果p+1==n
,那么兔子就该往p-1方向转移,相应p-1==n
,那么就往p+1方向走,这里要注意p的移动是否越界。
分析完事,就是代码的编写了,因为 1<=p<=d,我们就可以看成有d颗树,如果其中一个树的结果是false,那么就代表抓不到。
由于没有测试例子,我就简单的测试了一下题目中的举例通过而已,其他的后面在想办法去测试看看吧,感觉写得很烂,对比其他人写的…唉…
借用别人的测试例子:
4个洞,4次查找 2 2 3 3 ,找不到兔子
5次查找2 2 3 3 2 找到兔子。
本文来自 song2016 的CSDN 博客
,全文地址请点击:https://blog.csdn.net/song2016/article/details/81062247?utm_source=copy
代码:
//ary为序列,arylen为序列长度,n为序列位置,d为洞口数,pos为兔子起始位置
//记录n是为了在产生分支的情况下能够从正确的序列号开始
//如n一开始设置为0,第一次检查的洞口就是ary[n]
bool catchrabbit(int *ary,int arylen,int n,int d,int pos) {
if (pos > d) {
return true;
}
//下面需要修改到原参数,所以需要备份使用
int cnt = n, findp, nextfindp, tpos = pos;
int tmplen = arylen - cnt;//记录剩余的序列数量
bool is = true, con;
while (cnt<=tmplen) {
if (cnt == tmplen)
return false;
findp = ary[cnt];
if (cnt + 1 <= tmplen - 1) {
nextfindp = ary[cnt + 1];
}
else {
nextfindp = 0;
}
con = (tpos + 1 != nextfindp)&(tpos - 1 != nextfindp);
cnt++;
if (tpos == findp) {
is = true;
break;
}
//情况1
if (tpos - 1 < 0) {
tpos++;
}
else if (tpos + 1 > d) {
tpos--;
}
//情况3
else if ((tpos + 1 == nextfindp)&&(tpos-1>0)) {
tpos--;
}
else if ((tpos - 1 == nextfindp)&&(tpos+1<=d)) {
tpos++;
}
//情况2
else if (con) {
bool a = catchrabbit(ary, arylen, cnt, d, tpos-1);
bool b = catchrabbit(ary, arylen, cnt, d, tpos + 1);
is = is & a & b;
if (is == false)
return false;
break;
}
else {
tpos++;
}
}
//把1~d个洞的结果&起来
is = is & catchrabbit(ary, arylen, n, d, pos + 1);
return is;
}
int main()
{
int ary[] = { 2,2,3,3,2 };
int len = sizeof(ary) / sizeof(int);
bool is = catchrabbit(ary, len, 0, 4, 1);
if(is)
cout<<"YES";
else
cout<<"NO";
return 0;
}