問題描述:
假設有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...