一摞烙饼的排序问题--读书笔记(2)
2015-01-29 14:48
363 查看
问题描述:一摞大小不一的饼,由于一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们上下颠倒个,反复几次使烙饼安装由小到大排好序。假设有n块大小不一的饼,最少需要翻几次使烙饼排好序。
分析与解法:
首先,经过两次翻转可以把最大的烙饼翻转到最下面,因此,最多需要把上面的n-1个烙饼依次翻转两次。那么至多需2(n-1)次翻转就可以把所有烙饼排好序。当然还有更高效的方法,考虑每次翻转的时候,把两个本来应该相邻的烙饼尽可能的换到一起,当所有的烙饼都换到一起时,实际上已经完成了排序。因此,可以通过递归来进行求解。
递归的第一个退出条件是已经排好序,还有就是翻转次数多于2(n-1)就退出。在翻转的过程中,可以看看当前的烙饼数组的排序情况如何,然后利用这些信息帮助减少翻转次数。
每个状态还应该有翻转的最小次数,这个下限值可以这样确定:从最后一个位置开始,往前找到第一个与最终结果位置不同的烙饼编号(也就是说排除最后几个已经就位的烙饼),从该位置到第一个位置,计算相邻的烙饼的编号不连续的次数,再加上1。
代码如下:
分析与解法:
首先,经过两次翻转可以把最大的烙饼翻转到最下面,因此,最多需要把上面的n-1个烙饼依次翻转两次。那么至多需2(n-1)次翻转就可以把所有烙饼排好序。当然还有更高效的方法,考虑每次翻转的时候,把两个本来应该相邻的烙饼尽可能的换到一起,当所有的烙饼都换到一起时,实际上已经完成了排序。因此,可以通过递归来进行求解。
递归的第一个退出条件是已经排好序,还有就是翻转次数多于2(n-1)就退出。在翻转的过程中,可以看看当前的烙饼数组的排序情况如何,然后利用这些信息帮助减少翻转次数。
每个状态还应该有翻转的最小次数,这个下限值可以这样确定:从最后一个位置开始,往前找到第一个与最终结果位置不同的烙饼编号(也就是说排除最后几个已经就位的烙饼),从该位置到第一个位置,计算相邻的烙饼的编号不连续的次数,再加上1。
代码如下:
#include<stdio.h> #include<assert.h> class CPrefixSorting { public: CPrefixSorting() { m_nCakeCnt = 0; m_nMaxSwap = 0; } //计算烙饼翻转信息 //@param //pCakeArray 存储烙饼索引数组 //nCakeCnt 烙饼个数 void Run(int* pCakeArray,int nCakeCnt) { Init(pCakeArray,nCakeCnt); m_nSearch = 0; Search(0); } //输出烙饼具体翻转次数 void Output() { for(int i = 0; i < m_nMaxSwap; i++) { printf("%d", m_SwapArray[i]); } printf("\n |Search Times| : %d\n", m_nSearch); printf("Total Swap times = %d\n", m_nMaxSwap); } private: // //初始化数组信息 //@param //pCakeArray 存储烙饼索引数组 //nCakeCnt 烙饼个数 // void Init(int* pCakeArray,int nCakeCnt) { assert(pCakeArray != NULL); assert(nCakeCnt > 0); m_nCakeCnt = nCakeCnt; //初始化烙饼数组 m_CakeArray = new int[m_nCakeCnt]; assert(m_CakeArray != NULL); for(int i = 0; i < m_nCakeCnt; i++) { m_CakeArray[i] = pCakeArray[i]; } //设置最多交换次数信息 m_nMaxSwap = UpBound(m_nCakeCnt); //初始化交换结果数组 m_SwapArray = new int[m_nMaxSwap]; assert(m_SwapArray != NULL); //初始化中间交换结果信息 m_ReverseCakeArray = new int[m_nCakeCnt]; for(int i = 0; i < m_nCakeCnt; i++) { m_ReverseCakeArray[i] = m_CakeArray[i]; } m_ReverseCakeArraySwap = new int[m_nMaxSwap]; } // //寻找当前翻转的上界 // // int UpBound(int nCakeCnt) { return (nCakeCnt) * 2; } // //寻找当前翻转的下界 // // int Lower_Bound(int* pCakeArray,int nCakeCnt) { int t, ret = 0; //根据当前数组的排序信息情况来判断最少需要交换多少次 for(int i = 1; i < nCakeCnt; i++) { //判断位置相邻的两个烙饼,是否为尺寸排序上相邻的 t = pCakeArray[i] - pCakeArray[i-1]; if((t == 1) || (t == -1)) { } else { ret++; } } return ret; } // 排序的主函数 void Search(int step) { int i, nEstimate; m_nSearch++; //估算这次搜索所需要的最小交换次数 nEstimate = Lower_Bound(m_ReverseCakeArray,m_nCakeCnt); if(step + nEstimate >= m_nMaxSwap) return; //如果已经排好序,即翻转完成,输出结果 if(IsSorted(m_ReverseCakeArray,m_nCakeCnt)) { if(step < m_nMaxSwap) { m_nMaxSwap = step; for(i = 0; i < m_nMaxSwap; i++) m_SwapArray[i] = m_ReverseCakeArraySwap[i]; } return; } //递归进行翻转 for(int i = 1; i < m_nCakeCnt; i++) { Revert(0, i); m_ReverseCakeArraySwap[step] = i; Search(step + 1); Revert(0, i); } } // //true: 已经排好序 //false: 未排序 // bool IsSorted(int* pCakeArray,int nCakeCnt) { for(int i = 1; i < nCakeCnt; i++) { if(pCakeArray[i-1] > pCakeArray[i]) { return false; } } return true; } // //翻转烙饼信息 // void Revert(int nBegin,int nEnd) { assert(nEnd > nBegin); int i, j, t; //翻转烙饼信息 for(i = nBegin, j = nEnd; i < j; i++, j--) { t = m_ReverseCakeArray[i]; m_ReverseCakeArray[i] = m_ReverseCakeArray[j]; m_ReverseCakeArray[j] = t; } } private: int* m_CakeArray; //烙饼信息数组 int m_nCakeCnt; //烙饼个数 int m_nMaxSwap; //最多交换次数,根据前面的推断,这里最多为m_nCakeCnt*2 int* m_SwapArray; //交换结果数组 int* m_ReverseCakeArray; //当前翻转烙饼信息数组 int* m_ReverseCakeArraySwap; //当前翻转烙饼交换结果数组 int m_nSearch; //当前搜索次数信息 }; int main() { CPrefixSorting cpfs; int cakeArray[] = {3,2,1,6,5,4}; cpfs.Run(cakeArray,6); cpfs.Output(); }
相关文章推荐
- 《编程之美》读书笔记(二): 一摞烙饼的排序问题
- 《编程之美》读书笔记(三): 一摞烙饼的排序问题
- 编程之美 - 读书笔记 - 一摞烙饼的排序问题
- 编程之美1.3 一摞烙饼的排序(扩展问题)
- 《编程之美》读书笔记:一摞烙饼的排序
- 《编程之美》 -- 中国象棋将帅问题和一摞烙饼的排序
- 《编程之美》读书随笔之三:一摞烙饼的排序问题
- 编程之美 一摞烙饼的排序问题
- 读书笔记之编程之美 - 1.3 一摞烙饼的排序
- 编程之美笔记2 一摞烙饼的排序问题
- 一摞烙饼的排序----《编程之美》读书笔记
- 《编程之美》读书笔记(二):烙饼的排序问题(Java实现)
- 一摞烙饼的问题
- 关于烙饼排序问题的优化
- 《编程之美》一摞烙饼问题详解与纠错
- 编程之美1.3 一摞烙饼的排序
- 《编程之美》读书笔记02: 1.3 一摞烙饼的排序
- 编程之美学习笔记(三):一摞烙饼的排序
- 编程之美-- 烙饼排序问题
- 编程之美:一摞烙饼的排序