1.这是一个翻烙饼的问题:
一个饭馆的服务员,在每次客户点了烙饼的时候,
都会把烙饼按下面最大上面最小的顺序摆放好,由
于一只手托着盘子里的烙饼,只能用另一只手一次
抓住最上面的几个烙饼进行翻个儿。
求最优的翻烙饼方法(翻的次数最少)[详见《程序之美》]
2.建模:
书上给的算法没看懂,不过我觉得这个也可以实现,但肯定不是最优的。
每次翻转的时候的目标都是最大的烙饼,第一次先把最大的烙饼翻个儿到最上面,
然后再把它翻个到最下面,这样就完成了一个烙饼的翻个,接下来重复下面的N-1
个烙饼,直到全部翻转完成。
public class Flapjack { private static int[] arr = { 1, 4, 6, 8, 45, 2, 3, 9, 5, 6, 12, 4, 56, 7 }; private static int revertCount; /** * isSorted 是否已排序好 * * @param arr * @return */ private static boolean isSorted() { for (int i = 1; i < arr.length; i++) { if (arr[i - 1] > arr[i]) return false; } return true; } /** * getMaxItemIndex 获取数组中最大项的索引 * * @param end * @return */ private static int getMaxItemIndex(int end) { if (end > arr.length) throw new ArrayIndexOutOfBoundsException(); int temp = arr[0]; int index = 0; for (int i = 1; i < end; i++) { if (temp < arr[i]) { temp = arr[i]; index = i; } } return index; } /** * revert 翻转 * * @param begin * @param end */ private static void revert(int begin, int end) { if (begin > end || end > arr.length - 1 || begin < 0) return; for (int iBegin = begin, iEnd = end; iBegin < iEnd; iBegin++, iEnd--) { int temp = arr[iBegin]; arr[iBegin] = arr[iEnd]; arr[iEnd] = temp; } revertCount++; } /** * 排序主函数 * * @param len */ public static void sort(int len) { if (isSorted()) return; int maxIndex = getMaxItemIndex(len); revert(0, maxIndex); revert(0, len - 1); if (len <= 0) return; sort(len - 1); } /** * 打印 */ public static void print() { System.out.print("["); for (int i = 0; i < arr.length; i++) if (i == arr.length - 1) System.out.print(arr[i]); else System.out.print(arr[i] + ","); System.out.print("]"); System.out.println("翻转次数:" + revertCount); } /** * 测试 */ public static void main(String[] args) { System.out.println("排序前:"); Flapjack.print(); sort(arr.length); System.out.println("排序后:"); Flapjack.print(); } }?
如有更好的算法,欢迎讨论。