翻烙饼问题

问题描述: 有一摞烙饼,因为一只手端着盘子,所以只能用另外一只手来给烙饼排序,将烙饼由大到小排好序。这样就要求我们在给烙饼排序的时候总是将最上面的N个烙饼一起翻转。如果最下面的烙饼是最大的,那么只需要解决上面的N-1个烙饼,同理可以最后到解决两个烙饼的排序。

 

简单的排序方法:先找到最大的烙饼,将其和其以上的烙饼一起翻转,这样最大的烙饼就在盘子的最上面了,然后翻转所有的烙饼,这样最大的烙饼就在盘子的最下面了。同样的,处理剩下的N-1个烙饼,知道最后所有的烙饼都排好序。可以知道我们最多需要进行2*(N-1)次翻转就可以将所有的烙饼排好序。

 

问题? 如果减少烙饼的反转次数,达到一个最优的解。 加入这堆老兵中有几个不同的部分相对有序,凭直接来猜测,可以把笑一下的烙饼进行翻转,每次考虑翻转烙饼的时候总是把相邻的烙饼尽可能的放到一起。

 

解决方法: 通过穷举法来找所有可能方案中的最优方案,自然会用到动态规划或者递归的方法来实现。可以从不同的翻转策略开始,比如第一次先翻最小的,然后递归的把所有的可能都全部翻转一次。

 

既然2(N-1)是一个最多的翻转次数,就可以得知,如果算法中的翻转次数超过了2(N-1),我们就应该放弃这个算法。


/*
 * Sorting.cpp
 *
 *  Created on: 2014年2月7日
 *      Author: Eileen
 */


#include "Sorting.h"
#include <stdio.h>
#include <assert.h>
#include <iostream>
using  namespace std;


Sorting::Sorting(){
// TODO Auto-generated constructor stub
m_nCakeCnt = 0;
m_nMaxSwap = 0;
}


Sorting::~Sorting() {
// TODO Auto-generated destructor stub
}


void Sorting::Init(int* pCakeArray, int nCakeCnt){
assert(pCakeArray!=NULL);
assert(nCakeCnt > 0);


m_nCakeCnt = nCakeCnt;
m_CakeArray = new int[m_nCakeCnt];
assert(m_CakeArray !=NULL);
for(int i=0; i<m_nCakeCnt; i++)
{
m_CakeArray[i] = pCakeArray[i];
}
//设置最多交换次数信息
m_nMaxSwap = UpBound(m_nCakeCnt);
//初始化交换结果数组
m_SwapArray = new int[m_nMaxSwap];
assert(m_SwapArray != NULL);
//初始化中间交换结果信息
m_ReverseCakeArray = new int[m_nCakeCnt];
for(int i=0; i<m_nCakeCnt; i++)
{
m_ReverseCakeArray[i] = m_CakeArray[i];
}
m_ReverseCakeArraySwap = new int[m_nMaxSwap];
}


int Sorting::UpBound(int nCakeCnt){
return nCakeCnt*2;
}


int LowerBound(int* pCakeArray, int nCakeCnt){
int t, ret = 0;
//根据当前数组的排序信息情况来判断最少需要交换多少次
for(int i=1; i<nCakeCnt; i++)
{
t = pCakeArray[i] - pCakeArray[i-1];
if((t == 1) || (t == -1))
{
}
else
{
ret++;
}
}
return ret;
}




bool Sorting::IsSorted(int* pCakeArray, int nCakeCnt)
{
for(int i=1; i<nCakeCnt; i++)
{
if(pCakeArray[i-1] > pCakeArray[i])
{
return false;
}
}
return true;
}




void Sorting::Revert(int nBegin, int nEnd){
assert(nEnd > nBegin);


int i, j, t;


for(i = nBegin, j=nEnd; i<j; i++, j--)
{
t = m_ReverseCakeArray[i];
m_ReverseCakeArray[i] = m_ReverseCakeArray[j];
m_ReverseCakeArray[j] = t;
}
}


//排序的主函数
void Sorting::Search(int step){
int i, nEstimate;
m_nSearch++;


nEstimate = LowerBound(m_ReverseCakeArray, m_nCakeCnt);
if(step + nEstimate > m_nMaxSwap)
return;


if(IsSorted(m_ReverseCakeArray, m_nCakeCnt))
{
if(step < m_nMaxSwap)
{
m_nMaxSwap = step;
for(i = 0; i<m_nMaxSwap; i++)
m_SwapArray[i] = m_ReverseCakeArraySwap[i];
}
return;
}


for(i=1; i<m_nCakeCnt; i++)
{
Revert(0,i);
m_ReverseCakeArraySwap[step] = i;
Search(step+1);
Revert(0,i);
}
}


void Sorting::Run(int* pCakeArray, int nCakeCnt)
{
Init(pCakeArray, nCakeCnt);
m_nSearch = 0;
Search(0);
cout<< m_nMaxSwap <<endl;
for(int i=0; i<m_nMaxSwap; i++)
cout<< m_SwapArray[i];
}




  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值