一摞烙饼的问题

来源:互联网 发布:饥荒mac版怎么改语言 编辑:程序博客网 时间:2024/04/27 17:13

问题:

    星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯。程序员多喝了几杯之后谈什么呢?自然是算法问题。有个同事说:“我以前在餐馆打工,顾客经常点非常多的烙饼。店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好——小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个有趣的排序问题:假设有n块大小不一的烙饼,那最少要翻几次,才能达到最后大小有序的结果呢?”

你能否写出一个程序,对于n块大小不一的烙饼,输出最优化的翻饼过程呢?

解决方案:

《编程之美》上面给出的方法是通过递归寻找出最优方案。

递归结束条件有两个:

1)递归步骤超过最大步骤数;

2)已经有序。

但由于递归过程步骤过多,需要对其进行剪枝:

1)定上界:假设每次只将最大的翻到最下面(跟冒泡类似),至多需要2次翻转,总共有n-1个需要翻转(最后一个不用翻了),那么最多需要2*(n-1)次翻转;当然,为了减少更多不必要的遍历,每次找到一个实现了有序的步骤数step,则将max更新为该step。

2)定下界:每次递归时,计算当前所在状态下至少还需要多少次翻转,设为lowerbound, 如果当前已经翻转的步骤数step+lowerbound(已经翻转步骤数+当前状态下至少还需要的步骤数)超过了上届,则可以结束该次递归了。

下面是结合该想法,自己写的一个程序:

//============================================================================// Name        : 3_version1.cpp// Author      : yahohi// Version     :// Copyright   : All rights reserved// Description : Ansi-style//============================================================================#include <iostream>using namespace std;#define size 5int array[size] = {1,2,3,4,5};int nMax = 2*(size - 1);static int move[2*(size - 1)];bool isSorted(int len);void reverse(int begin, int end);void println(int a[], int len);int LowerBound(int a[], int s);void Search(int step){int lowerbound = LowerBound(array, size);if ((lowerbound + step) > nMax)return;if (isSorted(size)){cout << endl<< "step: " << step << endl;cout << "More details: " << endl;println(move, step);nMax = step;return;}//每一次都有size-1中翻的方法for (int i = 1;i < size;i ++){reverse(0,i);//翻前i个饼move[step] = i;Search(step + 1);reverse(0,i);//恢复现场}}int LowerBound(int a[], int s){int ret = 0;for (int i = 0;i < s - 1; i ++){if (abs(a[i] - a[i+1]) != 1)ret ++;}return ret;}bool isSorted(int len){bool ret = true;for (int i = 0;i < len-1; i ++){if (array[i] > array[i+1]){ret = false;break;}}return ret;}void reverse(int begin, int end){for (int i = begin;i < (begin+end + 1)/2; i++){int temp = array[i];array[i] = array[end - i];array[end - i] = temp;}}void println(int a[], int len){for (int i = 0;i < len; i ++){cout << a[i] << " ";}cout<<endl;}int main() {reverse(0,1);reverse(0,2);println(array, size);Search(0);return 0;}
其中,递归过程中的恢复现场尤为重要!

原创粉丝点击