1.3一摞烙饼的问题
生活随笔
收集整理的這篇文章主要介紹了
1.3一摞烙饼的问题
小編覺得挺不錯的,現在分享給大家,幫大家做個參考.
題目是這樣的:
星期五的晚上,一幫同事在希格瑪大廈附近的“硬盤酒吧”多喝了幾杯。程序員多喝了幾杯之后談什么呢?自然是算法問題。有個同事說:
“我以前在餐館打工,顧客經常點非常多的烙餅。店里的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好——小的在上面,大的在下面。由于我一只手托著盤子,只好用另一只手,一次抓住最上面的幾塊餅,把它們上下顛倒個個兒,反復幾次之后,這摞烙餅就排好序了。
我后來想,這實際上是個有趣的排序問題:假設有n塊大小不一的烙餅,那最少要翻幾次,才能達到最后大小有序的結果呢?
思想:
書上面給出的方法是通過遞歸尋找出最優方案。
遞歸結束條件有兩個:
1)遞歸步驟超過最大步驟數;
2)已經有序。
但由于遞歸過程步驟過多,需要對其進行剪枝:
1)定上界:假設每次只將最大的翻到最下面(跟冒泡類似),至多需要2次翻轉,總共有n-1個需要翻轉(最后一個不用翻了),那么最多需要2*(n-1)次翻轉;當然,為了減少更多不必要的遍歷,每次找到一個實現了有序的步驟數step,則將max更新為該step。
2)定下界:每次遞歸時,計算當前所在狀態下至少還需要多少次翻轉,設為lowerbound, 如果當前已經翻轉的步驟數step+lowerbound(已經翻轉步驟數+當前狀態下至少還需要的步驟數)超過了上界,則可以結束該次遞歸了。
代碼:
class CPrefixSorting { public:CPrefixSorting() {m_nCakeCnt = 0;m_nMaxSwap = 0;} ~CPrefixSorting() {if( m_CakeArray != NULL ) delete m_CakeArray;if( m_SwapArray != NULL ) delete m_SwapArray;if( m_ReverseCakeArray != NULL ) delete m_ReverseCakeArray;if( m_ReverseCakeArraySwap != NULL ) delete m_ReverseCakeArraySwap;}//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) cout << m_SwapArray[i] << " ";cout << "Search times: " << m_nSearch;cout << "Total swap times: " << m_nMaxSwap;}private://pCakeArray 存儲烙餅索引數組//nCakeCnt 烙餅個數void Init(int* pCakeArray, int nCakeCnt) {assert( pCakeArray != NULL );assert( nCakeCnt > 0 );m_nCakeCnt = nCakeCnt;//初始化烙餅數組m_CakeArray = new int[nCakeCnt];assert( m_CakeArray != NULL );for(int i = 0; i < nCakeCnt; ++i) m_CakeArray[i] = pCakeArray[i];//設置最多交換次數信息m_nMaxSwap = UpperBound(m_nCakeCnt);//初始化交換結果數組m_SwapArray = new int[m_nMaxSwap + 1];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 UpperBound(int nCakeCnt) { return nCakeCnt * 2; }//尋找當前翻轉的下界int LowerBound(int* pCakeArray, int nCakeCnt) {int ret = 0;//根據當前數組的排序信息情況來判斷最少需要交換多少次for(int i = 1; i < nCakeCnt; ++i) {//判斷位置相鄰的兩個烙餅,是否為尺寸排序上相鄰的int t = pCakeArray[i] - pCakeArray[i-1];if(t == 1 || t == -1) { }else ++ret;}return ret;}void Search(int step) {m_nSearch++;//估算這次搜索所需要的最小交換次數int nEstimate = LowerBound(m_ReverseCakeArray, m_nCakeCnt);if( step + nEstimate > m_nMaxSwap ) return ;//如果已經排好序,即翻轉完成,輸出結果if( IsSorted(m_ReverseCakeArray, m_nCakeCnt) ) {if( step < m_nMaxSwap) {m_nMaxSwap = step;for(int i = 0; i < m_nMaxSwap; ++i) m_SwapArray[i] = m_ReverseCakeArraySwap[i];}return ;}//遞歸進行翻轉for(int i= 1; i < m_nCakeCnt; ++i) {Reverse(0, i);m_ReverseCakeArraySwap[step] = i;search(step + 1);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) {assert( nBegin < nEnd );//翻轉烙餅信息for(int i = nBegin, j = nEnd; i < j; ++i, --j) {int temp = m_ReverseCakeArray[i];m_ReverseCakeArray[i] = m_ReverseCakeArray[j];m_ReverseCakeArray[j] = temp;}}private:int* m_CakeArray; //烙餅信息數組int m_nCakeCnt; //烙餅個數int m_nMaxSwap; //最多交換次數,根據前面的推斷,這里最多為m_nCakeCnt*2int* m_SwapArray; //交換結果數組int* m_ReverseCakeArray; //當前翻轉烙餅信息數組int* m_ReverseCakeArraySwap; //當前翻轉烙餅交換結果數組int m_nSearch; //當前搜索次數信息 };
總結
以上是生活随笔為你收集整理的1.3一摞烙饼的问题的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: matlab极性电容叫什么,有极性电容和
- 下一篇: 新海诚画集[秒速5センチメートル:樱花抄