一摞烙饼的排序问题--读书笔记(2)
生活随笔
收集整理的這篇文章主要介紹了
一摞烙饼的排序问题--读书笔记(2)
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
問題描述:一摞大小不一的餅,由于一只手托著盤子,只好用另一只手,一次抓住最上面的幾塊餅,把它們上下顛倒個,反復幾次使烙餅安裝由小到大排好序。假設有n塊大小不一的餅,最少需要翻幾次使烙餅排好序。
分析與解法:
首先,經過兩次翻轉可以把最大的烙餅翻轉到最下面,因此,最多需要把上面的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*2int* 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(); }
總結
以上是生活随笔為你收集整理的一摞烙饼的排序问题--读书笔记(2)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 办公技巧整合(不定时更新)
- 下一篇: 虚拟独享服务器,独享云虚拟主机和服务器