日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

编程之美学习笔记--一摞烙饼的排序

發(fā)布時間:2023/12/8 编程问答 49 豆豆
生活随笔 收集整理的這篇文章主要介紹了 编程之美学习笔记--一摞烙饼的排序 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

問題:假設有n塊大小不一的烙餅,翻烙餅時只能從最上面的烙餅開始,一次抓住最上面的幾塊餅,把它們上下顛倒個兒,那么最少要翻多少次,才能夠達到最后的大小有序?

思路

先上一張圖,可以很好的說明思路:

假設有四張無序的餅,那么問題就變成了找到使層數(shù)最小的結點。書中給出的思路是:
將烙餅從第二張開始一個一個的嘗試去翻,采用深度優(yōu)先搜索的策略。在搜索開始之前,先找到了一種完成任務的方式,最少需要2*(n_cake-1)步。這就是一個搜索的上界,如果搜索步驟超過了這個上界,則這一枝可以拋棄不用搜索了,如果搜索到了一種翻轉方式,則將這種翻轉方式的翻轉次數(shù)更新為新的搜索上界值,以減小搜索范圍;同時給出了計算搜索下界的計算方式:當前狀態(tài)翻轉到有序狀態(tài)的步驟數(shù)目下界:若當前狀態(tài)中,還有m對烙餅沒有相鄰,而每次翻轉最多只能使得一個烙餅與大小跟它相鄰的烙餅拍到一起,故至少還要m次才能排好,如果當前搜索步數(shù)加上這個下界的值超過了搜索上界值,則在該枝的搜索就不必進行了。
搜索時,循環(huán)進行每一個子樹的搜索,循環(huán)中使用遞歸方式搜索;程序如下:

#include <stdio.h> #include <stdlib.h>class CakeSort { private:int* m_CakeArray; //初始烙餅數(shù)組int m_CakeCount; //烙餅數(shù)量int m_MaxSwap; //交換上界int m_SwapTimes; //已交換的次數(shù)int* m_SwapArray; //交換信息int* m_ReverseCake; //執(zhí)行交換后的烙餅數(shù)組int* m_SwapReverseCake; //執(zhí)行交換后的烙餅數(shù)組的交換信息int* m_SortArray; //排序完成的烙餅數(shù)組結果public:void Init(int* pCakeArray,int count);void Run(int* pCakeArray,int count);int UpperBound(int count);int LowerBound(int* pArray,int count);void Search(int step);bool IsSort(int* pArray,int count);void Reverse(int begin,int end);~CakeSort(void); }; void CakeSort::Init(int* pCakeArray,int count) {m_CakeCount = count;m_CakeArray = new int[count];for(int i = 0 ; i < count ; i++)m_CakeArray[i] = pCakeArray[i];m_ReverseCake = new int[count];for(int i = 0 ; i < count ; i++)m_ReverseCake[i] = m_CakeArray[i];m_MaxSwap = UpperBound(count);m_SwapTimes = 0;m_SwapArray = new int[m_MaxSwap];m_SwapReverseCake = new int[m_MaxSwap];m_SortArray=new int [m_CakeCount]; } int CakeSort::UpperBound(int count) {return 2*(count - 1); }//當前狀態(tài)翻轉到有序狀態(tài)的步驟數(shù)目下界:若當前狀態(tài)中,還有m對烙餅沒有相鄰,而每次翻轉最多只能 //使得一個烙餅與大小跟它相鄰的烙餅拍到一起,故至少還要m次才能排好 int CakeSort::LowerBound(int* pArray,int count) {int ret = 0 ;int t;for(int i = 1 ; i < count ; i++){t = pArray[i] - pArray[i-1];if((t != 1) && ( t!= -1))ret++;}return ret; } void CakeSort::Run(int* pArray,int count) {Init(pArray,count);Search(0);//打印最優(yōu)排序方式printf("最優(yōu)翻轉方式:\n");for (int i = 0; i < m_MaxSwap; i++) printf("%d\n", m_SwapArray[i]); printf("Search Times : %d\n", m_SwapTimes); printf("Total Swap times = %d\n", m_MaxSwap); //打印排序結果for (int i=0;i<m_CakeCount;i++){printf("cake:%d\n",m_SortArray[i]);}} void CakeSort::Reverse(int begin , int end) {int i,j,temp;for(i = begin , j = end ; i < j ; i++ , j--){temp = m_ReverseCake[i];m_ReverseCake[i] = m_ReverseCake[j];m_ReverseCake[j] = temp;} }//排列好后,返回真值 bool CakeSort::IsSort(int* pArray,int count) {for(int i = 1 ; i < count ; ++i){if(pArray[i] < pArray[i-1])return false;}return true; } void CakeSort::Search(int step) {m_SwapTimes++;int Est = LowerBound(m_ReverseCake,m_CakeCount);if(Est + step >= m_MaxSwap)return;if(IsSort(m_ReverseCake,m_CakeCount)){if(step <= m_MaxSwap){m_MaxSwap = step;//打印翻轉方式for(int i = 0 ; i < m_MaxSwap ; i ++){m_SwapArray[i] = m_SwapReverseCake[i];printf("%d\n",m_SwapArray[i]);}//打印該翻轉方式下的排序結果for (int i=0;i<m_CakeCount;i++){//想要保存正確的翻轉結果,需要另建數(shù)組保存,不然m_ReverseCake還會在其他函數(shù)中修改,最后m_ReverseCake中不會保留正確的翻轉結果m_SortArray[i]=m_ReverseCake[i];printf("cake:%d\n",m_ReverseCake[i]);}}return;}//沒有排列好的情況for(int i = 1 ; i < m_CakeCount ; i++){Reverse(0,i);//記錄本次操作的下標m_SwapReverseCake[step] = i;Search(step+1);//若第step+1步的翻轉失敗,回復到第step步的翻轉結果Reverse(0,i);} } int main() {int a[] = {3, 2, 1, 6, 5, 4, 9, 8, 7, 0}; CakeSort s;s.Run(a,10);system("pause");return 0; }CakeSort::~CakeSort(void) {if(m_CakeArray!=NULL)delete []m_CakeArray;if(m_SwapReverseCake!=NULL)delete []m_SwapReverseCake;if(m_SwapArray!=NULL)delete []m_SwapArray;if(m_ReverseCake!=NULL)delete []m_ReverseCake;if(m_SortArray!=NULL)delete []m_SortArray; }

從上述程序的輸出結果中可以看出,其實程序還是搜索了很多不必要的路徑,如剛剛將頭兩張烙餅翻轉,下一步馬上又把頭兩張餅翻轉過來,顯然是重復了,就沒有再向下搜索的必要了,因此可以繼續(xù)優(yōu)化,進一步減小搜索范圍
這里我們采用的想法是:上一步翻轉過的前i張餅,在下一次迭代時,直接跳過翻轉前i張餅的情況(因為這樣又會恢復到上一步的狀態(tài)),因此我們將:Search遞歸函數(shù)修改為:

void CakeSort::Search(int step,int flapIndex) {m_SwapTimes++;int Est = LowerBound(m_ReverseCake,m_CakeCount);if(Est + step >= m_MaxSwap)return;if(IsSort(m_ReverseCake,m_CakeCount)){if(step <= m_MaxSwap){m_MaxSwap = step;//打印翻轉方式for(int i = 0 ; i < m_MaxSwap ; i ++){m_SwapArray[i] = m_SwapReverseCake[i];printf("%d\n",m_SwapArray[i]);}//打印該翻轉方式下的排序結果for (int i=0;i<m_CakeCount;i++){//想要保存正確的翻轉結果,需要另建數(shù)組保存,不然m_ReverseCake還會在其他函數(shù)中修改,最后m_ReverseCake中不會保留正確的翻轉結果m_SortArray[i]=m_ReverseCake[i];printf("cake:%d\n",m_ReverseCake[i]);}}return;}//沒有排列好的情況for(int i = 1 ; i < m_CakeCount ; i++){if(flapIndex==i)continue;Reverse(0,i);//記錄本次操作的下標m_SwapReverseCake[step] = i;Search(step+1,i);//若第step+1步的翻轉失敗,回復到第step步的翻轉結果Reverse(0,i);} }

相應的,run函數(shù)修改為:

void CakeSort::Run(int* pArray,int count) {Init(pArray,count);Search(0,0);//打印最優(yōu)排序方式printf("最優(yōu)翻轉方式:\n");for (int i = 0; i < m_MaxSwap; i++) printf("%d\n", m_SwapArray[i]); printf("Search Times : %d\n", m_SwapTimes); printf("Total Swap times = %d\n", m_MaxSwap); //打印排序結果for (int i=0;i<m_CakeCount;i++){printf("cake:%d\n",m_SortArray[i]);}}

雖然可以避免一部分無用搜索,但是還是會存在無用的搜索。

總結

以上是生活随笔為你收集整理的编程之美学习笔记--一摞烙饼的排序的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。