《编程之美》之一摞烙饼的排序

星期五的晚上,一帮同事在希格玛大厦附近的“硬盘酒吧”多喝了几杯,程序员多喝了几杯之后谈什么呢?自然是算法

问题。有个同事说:

“我以前在餐厅打工,顾客经常点非常多的烙饼。店里的烙饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小

次序摆好---小的在上面,大的在下面。由于我一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们

上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了。我后来想,这实际上是个有趣的排序问题:假设有n块大小

不一的摞饼,那最少要翻几次,才能达到大小有序的结果呢?”

从这段描述中我们可以很容易的就把问题抽象出来:给你一个由 n 个连续整数组成的数组,数组是无序的,现在要你

对这个数组进行升序排序,但只能对数组进行一种操作,就是只能对从数组第一个元素开始到数组中任意一个元素之

间的所有元素进行翻转。只是这样的话,问题还不是很麻烦。这里还要求我们写程序输出最优的翻转过程。

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>

class CPrefixSorting
{
public:
	int * m_SwapArray;
	int * m_SwapTempArray;
	int * m_PieTempArray;
	int m_nPieCount;
	int * m_PieArray;
	int m_nMaxSwapCount;

public:
	CPrefixSorting()
	{
	}

	virtual ~CPrefixSorting()
	{
	}

public:
	void OutPut()
	{
		for (int i = 0; i < m_nMaxSwapCount; i++)
		{
			printf("%d\n", m_SwapArray[i]);
		}
	}

	/*遍历搜寻所有解法*/
	bool Search(int nStep)
	{
		/*剪枝:如果比最普通的解法还要差劲,干脆舍弃*/
		int nMinTimes = LowerBound(m_PieTempArray, m_nPieCount);
		if (nStep + nMinTimes > m_nMaxSwapCount)
		{
			return false;
		}

		if (IsSorted())
		{
			/*如果找到一个更优解法,则保存这个更优的解法*/
			if (nStep < m_nMaxSwapCount)
			{
				m_nMaxSwapCount = nStep;
				for (int i = 0; i < m_nMaxSwapCount; i++)
				{
					m_SwapArray[i] = m_SwapTempArray[i];
				}
			}
			return true;
		}

		/*颠倒此次烙饼后,遍历接下来全部可能的颠倒情况*/
		for (int i = 1; i < m_nPieCount; i++)
		{
			Reverse(0, i);
			m_SwapTempArray[nStep] = i;
			Search(nStep + 1);
			Reverse(0, i);
		}
	}

	bool IsSorted()
	{
		for (int i = 0; i < m_nPieCount - 1; i++)
		{
			if (m_PieTempArray[i] > m_PieTempArray[i + 1])
			{
				return false;
			}
		}
		return true;
	}

	void Init(int* pPieArray, int nPieCount)
	{
		assert(NULL != pPieArray);
		assert(0 < nPieCount);

		m_PieArray = new int[nPieCount];
		assert(NULL != m_PieArray);
		m_PieTempArray = new int[nPieCount];
		assert(NULL != m_PieTempArray);
		m_nPieCount = nPieCount;

		for (int i = 0; i < nPieCount; i++)
		{
			m_PieArray[i] = pPieArray[i];
			m_PieTempArray[i] = pPieArray[i];
		}

		m_nMaxSwapCount = UpperBound(nPieCount);
		m_SwapArray = new int[m_nMaxSwapCount];
		assert(NULL != m_SwapArray);
		m_SwapTempArray = new int[m_nMaxSwapCount];
		assert(NULL != m_SwapTempArray);
	}

	void Reverse(int nBegin, int nEnd)
	{
		assert(nBegin < nEnd);
		int i, j, t;
		for (i = nBegin, j = nEnd; i < j; i++, j--)
		{
			t = m_PieTempArray[i];
			m_PieTempArray[i] = m_PieTempArray[j];
			m_PieTempArray[j] = t;
		}
	}

	void Run(int* pPieArray, int nPieCount)
	{
		Init(pPieArray, nPieCount);
		Search(0);
		OutPut();
	}

	int UpperBound(int nPieCount)
	{
		return (nPieCount - 1) * 2;
	}

	int LowerBound(int* pPieArray, int nPieCount)
	{
		int ret = 0, t;
		for (int i = 0; i < m_nPieCount - 1; i++)
		{
			t = pPieArray[i] - pPieArray[i+1];
			if (t == 1 || t == -1)
			{
				continue;
			}
			ret++;
		}
		return ret;
	}
};

int main()
{
	CPrefixSorting stSort;
	int pPieArray[10] = {3,4,0,1,2,6,5,8,7,9};
	stSort.Run(pPieArray, 10);
	system("pause");
	return 0;
}

  

《编程之美》之一摞烙饼的排序

时间: 2024-11-08 17:35:08

《编程之美》之一摞烙饼的排序的相关文章

编程之美——一摞烙饼的排序(暴搜+剪枝)

题目 分析 深度优先搜索遍历每一种情况,去翻转次数最小的,当然,还要加一些剪枝,毕竟O(nn)的时间复杂度. 代码 C风格 1 /**** 前缀排序 ****/ 2 #include<stdio.h> 3 #include<cstring> 4 #include<algorithm> 5 using namespace std; 6 7 const int maxn = 100 + 10; 8 int n, arr[maxn]; //烙饼个数和烙饼数组 9 int ar

编程之美之一摞烙饼的排序1

拿到这个问题, 第一反应是利用分治的算法思想, 每次把当前的最大的一块烙饼放到指定位置 ,这样的思想非常简单,实现也非常容易.但是这只是提供了,问题的一个可行解,看完书中的内容之后发现,题目中要求的是最优化的输出过程,我们的这种方法显然没有考虑到优化<-_->!! 其实,我觉得就算我看到了这个最优化输出的要求,估计也想不到书中的设计思想的了.过段时间,等自己把书中的思想忘掉之后,再看看能不能想到这种算法思想吧.这应该算是埋了个坑吧 <-_->!! 这里将自己的代码贴出来: // =

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

编程之美书中讲的一摞烙饼的排序一题 这里无法用基本的排序方法对其排序,那么最直接的方法是找出N个数种最大者,将这通过两次翻转放置到最底部,然后处理N-1,N-2等,直到全部排序完,所以一共需要交换2(N-1)次 void reverse(int cakes[], int beg, int end) { int temp; while(beg < end){ temp = cakes[beg]; cakes[beg++] = cakes[end]; cakes[end--] = temp; } }

第1章 游戏之乐——一摞烙饼的排序

一摞烙饼的排序 问题:写出一个程序,对于n块大小不一的烙饼,输出最优化的翻饼过程?要保证烙饼按照大小次序摆好——小的在上面,大的在下面. 分析与解法: 用java实现的代码如下: package chapter1youxizhilePrefixSorting; import java.util.Scanner; /** * 一摞烙饼的 * @author DELL * */ public class PrefixSorting { private int[] m_CakeArray; //烙饼信

编程之美——1.3一摞烙饼的排序

//自己看到这个问题后的解法#include<iostream> using namespace std; typedef int status; //将一个数组p的坐标0到i的元素调个头 status diao_tou(int *p,int i) { if(i==0) return 1; for(int j=0;j<=((i-1)/2);j++) { int temp; temp=p[i-j]; p[i-j]=p[j]; p[j]=temp; } return 1; } int mai

编程之美—烙饼排序问题(JAVA)

一.问题描述 星期五的晚上,一帮同事在希格玛大厦附近的"硬盘酒吧"多喝了几杯.程序员多喝了几杯之后谈什么呢?自然是算法问题.有个同事说:"我以前在餐      馆打工,顾客经常点非常多的烙饼.店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好--小的在上面,大的在下面.由于我      一只手托着盘子,只好用另一只手,一次抓最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了.我后来想,这实际上是个     有趣的排序问题:假设有n块大小不一

leetcode&amp;编程之美——博文目录

leetcode刷题整理: 1——Two Sum(哈希表hashtable,map) 2——Add Two Numbers(链表) 3——Longest Substring Without Repeating Characters(set,哈希表,两个指针) 9——Palindrome Number (数学问题) 11——Container With Most Water(两个指针) 12——Integer to Roman(string,数学问题) 13——Roman to Integer(s

【编程之美】目录

第1章  游戏之乐——游戏中碰到的题目 1.1 让CPU占用率听你的指挥 1.2 中国象棋将帅问题 1.3 一摞烙饼的排序 1.4 买书问题 第2章  数字之魅——数字中的技巧 2.1 求二进制中1的个数 2.2 不要被阶乘吓倒 2.3 寻找发帖"水王" 2.4 1的数目 2.5 寻找最大的K个数 2.6 精确表达浮点数 2.7 最大公约数问题 2.8 找符合条件的整数 2.9 斐波那契(Fibonacci)数列 2.10 寻找数组中的最大值和最小值 2.11 寻找最近点对 2.12

编程之美-翻烙饼Java实现

从今天开始每天至少一个算法. 前言 翻烙饼问题是非常经典的问题,星期五的晚上,一帮同事在希格玛大厦附近的"硬盘酒吧"多喝了几杯.程序员多喝了几杯之后谈什么呢?自然是算法问题.有个同事说: "我以前在餐馆打工,顾客经常点非常多的烙饼.店里的饼大小不一,我习惯在到达顾客饭桌前,把一摞饼按照大小次序摆好--小的在上面,大的在下面.由于我一只手托着盘子,只好用另一只手,一次抓住最上面的几块饼,把它们上下颠倒个个儿,反复几次之后,这摞烙饼就排好序了. 我后来想,这实际上是个有趣的排序问