程式設計之美 遊戲之樂 一摞烙餅的排序

2021-09-28 19:57:25 字數 2857 閱讀 8483

問題描述

假設有n個大小不一的烙餅,那最少要翻幾次,才能達到大小有序的結果呢?寫乙個程式,對於n塊大小不一的烙餅,輸出最有的翻餅過程。

問題分析與解法

如果我們最底層的餅已經排序完畢,那麼我們只處理上面的n-1個餅就行,同樣的之後我們再把n-1個餅的排序轉化為n-2,n-3直到最後的兩個餅排好順序。

也就是說?第一輪:我們先找到這n個餅中的最大的餅,然後從該處進行翻餅,把這個最大的餅翻到最上面,然後再把所有的餅進行一次翻滾,這樣    最大的餅就翻到了最下面。

第二輪:我們上一輪已經把最大的餅翻到最下面了,接著我們用同樣的方法對待上面的n-1個餅,我們在這n-1個餅中找到最大的餅,然後    用同樣的方法把其翻滾到最底層的上面那一層(倒數第二層)。

一直到最後一輪只剩下兩個。

上面的那個方案注意,每一輪都翻滾了兩次,一共需要n-1輪(最後一輪剩下兩個,最後小的不需要再進行翻滾),那麼這個方案最多需要2(n-1)次翻滾。

如果在演算法中,需要翻轉的次數多於2(n-1)次,就應該放棄該演算法,直接退出。

另外,既然是乙個排序問題,也應該利用排序的資訊來處理,同樣,在翻轉的過程中,可以看看當前的烙餅陣列排序情況如何,然後利用這些資訊來減少翻轉次數。

**如下:

// cprefixsorting.cpp : 此檔案包含 "main" 函式。程式執行將在此處開始並結束。

//烙餅排序實現

#include #include using namespace std;

class cprefixsorting

~cprefixsorting()

if (m_swaparray != null)

if (m_reversecakearray != null)

if (m_reversecakearrayswap != null)

}/* 計算烙餅翻轉資訊

@param

pcakearray 儲存烙餅索引陣列

pcakecnt 烙餅數量

*/ void run(int* pcakearray, int ncakecnt)

/* 輸出烙餅具體翻轉的次數

*/ void output()

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)

//設定最多交換次數資訊

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_reversecakearrayswap = new int[m_nmaxswap];

} /*

尋找當前翻轉的上屆

*/ int upperbound(int ncakecnt)

/* 尋找當前翻轉的下屆

*/ int lowerbound(int* pcakearray, int ncakecnt)

else

} return ret;

} /*

排序的主函式

*/ void search(int step)

}return;

} //遞迴進行翻轉

for (int i = 1; i < m_ncakecnt; i++)

}/* true:已經排好序

false:未排序

*/ bool issorted(int* pcakearray, int ncakecnt)

} return true;

} /*

翻轉烙餅資訊

*/ void reverse(int nbegin, int nend)

}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()

; int m_ncakecount = 10;

pfs.run(m_cakearray, m_ncakecount);

pfs.output();

return 0;

}

每一次翻轉我們最多使得乙個烙餅與大小跟它相鄰的烙餅排到一起。如果當前n個烙餅中,有m對相鄰的烙餅半徑不相鄰,那麼我們至少需要。m次才能排好序。

注意:對於任意次序的n個餅的排列,目前研究的結果是上界最小為(5n+5)/3向上取整,下界最大為15n/14向上取整。用這個上下界的搜尋次數更少,效率更高(n較大時)。

程式設計之美 一摞烙餅排序

問題 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用另乙...

程式設計之美 一摞烙餅的排序

問題描述 星期五的晚上,一幫同事在希格瑪大廈附近的 硬碟酒吧 多喝了幾杯。程式設計師多喝了幾杯之後談什麼呢?自然是演算法問題。有個同事說 我以前在餐館打工,顧客經常點非常多的烙餅。店裡的餅大小不一,我習慣在到達顧客飯桌前,把一摞餅按照大小次序擺好 小的在上面,大的在下面。由於我乙隻手托著盤子,只好用...

程式設計之美 一摞烙餅的排序

先想了乙個最簡單的方法 首先對n個烙餅進行處理,找到最大的那個烙餅,將其之上的進行翻轉,然後對前n個烙餅堆進行翻轉 第二次操作對上面n 1個烙餅進行操作,還是找到n 1個中最大的,將其之上的進行翻轉,然後對前n 1個烙餅堆進行翻轉。這樣總共進行n 1次,每次翻轉兩次orz view code 1 i...