编程之美 1.3 一摞烙饼的排序
生活随笔
收集整理的這篇文章主要介紹了
编程之美 1.3 一摞烙饼的排序
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
一摞烙餅的排序
????有大小不一的一摞餅在你的一只手上,現在你需要將餅由大到小翻轉,即最大尺寸的餅在底部,最小尺寸的餅在最上面,而且你只能用一只手進行翻轉。千言萬語不如一張圖。
????上圖是三張餅的翻轉,你是否能寫出一個程序,對于n塊大小不一的烙餅,輸出最優化的翻餅過程?
解題思路:
1、 最笨的辦法,一次翻轉一個未排序中最大的餅需要兩次翻轉,那么n個餅就需要2*(n-1)次。當然這是最多的次數。
2、 萬一翻轉之前部分餅的順序已經是排好的了,如此一想,這種情況下那翻轉次數肯定會更少,但是這種情況還是比較難找。
3、 要找出最好的辦法,最笨的辦法,窮舉吧!當然窮舉的過程為了縮短次數,當以已經翻轉的次數大于2*(n-1)那么那次窮舉就可以停止了。跟進一步對當前序列進行翻轉次數預估,預估次數加上已翻轉次數大于2*(n-1),那么那次窮舉就可以停止了。
????窮舉的思路:上圖。從左到有是:頂端-底端。
源碼:
#include <iostream>using namespace std;class CPrefixSorting { private:int* m_CakeArray; // 烙餅信息數組int m_nCakeCnt; // 烙餅個數int m_nMaxSwap; // 最多交換次數,根據前面的推斷,這里最多為 m_nCakeCnt*2int* m_SwapArray; // 交換結果數組int* m_ReverseCakeArray; // 當前翻轉烙餅信息數組int* m_ReverseCakeArraySwap; // 當前翻轉烙餅交換結果數組int m_nSearch; // 當前搜索次數信息 public:CPrefixSorting(){m_nCakeCnt = 0;m_nMaxSwap = 0;}~CPrefixSorting(){delete m_CakeArray;delete m_SwapArray;delete m_ReverseCakeArray;delete m_ReverseCakeArraySwap;}// 初始化烙餅信息:個數void init(int *pCakeArray, int nCakeCnt){// 初始化烙餅數組m_nCakeCnt = nCakeCnt;m_CakeArray = new int[nCakeCnt];for (int i = 0; i < m_nCakeCnt; ++i){m_CakeArray[i] = pCakeArray[i];}// 設置最多交換次數信息m_nMaxSwap = UpperBound(m_nCakeCnt);// 初始化交換結果數組m_SwapArray = new int[m_nMaxSwap];// 初始化中間交換結果信息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];}void run(int*pCakeArray, int nCakeCnt){init(pCakeArray, nCakeCnt);m_nSearch = 0;search(0);}// 輸出烙餅具體翻轉次數void output(){for (int i = 0; i < m_nMaxSwap; ++i){cout << m_SwapArray[i]<<" ";}cout << endl << "|Search Times| :" << m_nSearch <<endl;cout << "Total Swap times = " << m_nMaxSwap << endl;}// 尋找當前翻轉的上界int UpperBound(int nCakeCnt){return nCakeCnt * 2;}// 尋找當前翻轉的下界int lowerBound(int* pCakeArray, int nCakeCnt){int t, ret = 0;// 根據當前數組的排序信息情況來判斷最少需要交換多少次 // 要求餅大小間隔為1,故有待改進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 = lowerBound(m_ReverseCakeArray, m_nCakeCnt); // 預估次數加已翻轉次數大于m_nMaxSwap就退出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_CakeArray[m_ReverseCakeArraySwap[i]];}}return;}// 遞歸進行翻轉for (i = 1; i < m_nCakeCnt; ++i){// 翻轉頂部餅到第i個餅reverse(0, i);// 記錄翻轉第i個餅序號m_ReverseCakeArraySwap[step] = i;// 進行下一輪翻轉窮舉search(step + 1);//若第step+1步的翻轉失敗,回復到第step步的翻轉結果reverse(0, i);}}// 是否排好序bool isSorted(int* pCakeArray, int nCakeCnt){for (int i = 1; i < nCakeCnt; ++i){if (pCakeArray[i - 1] > pCakeArray[i]){return false;}}return true;}// 翻轉烙餅信息void reverse(int nBegin, int nEnd){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;}} };int main() {int CakeArray[] = {4,2,3,1,5,6,7,9,8}; //頂端-底端int size = sizeof(CakeArray) / sizeof(CakeArray[0]);CPrefixSorting a;a.run(CakeArray,size);a.output();getchar();return 0; }總結
以上是生活随笔為你收集整理的编程之美 1.3 一摞烙饼的排序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 3dmax入门
- 下一篇: python 从大到小循环_跟老齐学Py