问题
一堆大小不一的烙饼,每次只能翻转最上面的几个饼,通过几次翻转使小的烙饼在上面大的烙饼在下面,寻找翻转次数最少的方法
分析
这是一个排序问题,但是只能通过翻转实现。把一叠饼的顺序看成一个状态。每一次的翻转,可以看成一种状态引发出另一个状态,在不同地方翻转会生出不同的状态,不同状态继续翻转生成更多的状态,把初始状态看成根节点,这样会生成一棵无止境的树。寻找翻转次数最少的方法即寻找靠近根节点的状态为已经有序的节点。
为了减少查找的次数,要是能找到一个边界,超出这个边界的节点不用搜索就好了,也就是剪枝。
书中提供了两个边界:
1.上边界(至多可以翻几次使烙饼有序)
- 翻最大的饼,把最大的饼翻到最上面,然后翻到最下面(2次)
- 对剩余的饼重复上述操作
- 如果只有2张饼,至多翻1次可使饼有序
- 这样的话,翻的次数为2*(n-2)+1,n>=2
最后的最优解肯定是少于上边界的,
2.下边界(至少还要翻几次使现状态的烙饼有序)
如果现阶段的已经翻的次数+下边界>上边界的话,也不用考虑这条路径了,肯定不是最优解
思路
初始化最优解为边界1,遍历所有在界限内的状态,如果找到了比当前最优解好的路径,就更新最优解。采用深度优先遍历。
代码
因为我平时写的大多是javaScript,所以代码是javaScript实现的,可能和书上的有些出入。
需要存储的信息:
两个边界:
辅助的方法:
核心的方法:
|
|
扩展问题
1.可以把上面的一摞饼放头上,然后再处理其它饼,算法的改动?
可以把一摞饼放头上,意味着翻转的部分可以是这摞饼的任意一部分,翻转部分的起点不一定是首个元素了,遍历的时候,还得遍历不同首部,以包括所有的情况
2.饼的正反有序,算法的改动?
是否有序有变化,需要修改isSorted函数;而翻转的过程,饼的正反也变动了,需要修改reverse函数,而且翻转最上面的1个饼,也会使饼的状态变化,所以需要修改遍历的起始范围。
烙饼的格式:
是否有序:
翻转函数:
遍历的上界:
每次把最大的饼翻上来,再翻一次使之反面朝上,再翻一次使之到底部(3次)
重复操作,必能完成翻饼的任务
遍历的起始位置:
3.希望翻转的烙饼数最小?
遍历的时候不是找离根节点最近的点,更新最优解的条件变了,同时边界也变了,这里我取的上边界为(n*n+n),下边界为(1.5n-0.5),这个边界不是很理想,以致对[3,2,1,6,5,4,7,0]的序列程序搜索了6861032次,但是我没想到其它的边界条件
搜索函数加了一点改进:
总结
翻烙饼的问题就这样了,下次再见了