如何找到这个问题的最优解呢?
每次都把当前最大的和上面的馅饼一起翻转,这样最多需要翻转2(n-1)次即可完成馅饼的翻转。
如果馅饼中有好几个不同的部分已经相对有序,每次翻转时,把两个本来应该相邻的烙饼尽可能的换到一起。
此问题本质上是对剪枝函数进行修改:设定上界和下届。
代码如下:
#ifndef XINBINGSORT_H_INCLUDED
#define XINBINGSORT_H_INCLUDED
#include<cassert>
#include<stdio.h>
//烙饼排序实现
class CPrefixSorting
{
public:
CPrefixSorting()
{
m_nCakeCnt=0;
m_nMaxSwap=0;
}
~CPrefixSorting()
{
if(m_CakeArray!=NULL)
{
delete m_CakeArray;
}
if(m_SwapArray!=NULL)
{
delete m_SwapArray;
}
if(m_ReverseCakeArray!=NULL)
{
delete m_ReverseCakeArray;
}
if(m_ReverseCakeArraySwap!=NULL)
{
delete m_ReverseCakeArraySwap;
}
}
//计算烙饼翻转信息
void Run(int* pCakeArray,int nCakeCnt)
{
Init(pCakeArray,nCakeCnt);
m_nSearch=0; //搜索次数设置为0
Search(0);
}
//输出烙饼具体翻转次数
void Output()
{
for(int i=0;i<m_nMaxSwap;i++)
{
printf("%d ",m_SwapArray[i]); //输出交换结果数组的值
}
printf("\n |Search Times| :%d\n",m_nSearch);
printf("Total Swap times=%d\n",m_nMaxSwap);
}
private:
//初始化数组信息
void 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=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_ReverseCakeArray[i]=m_CakeArray[i];
}
m_ReverseCakeArraySwap=new int[m_nMaxSwap];
}
//寻找当前翻转的上界
int UpperBound(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;
}
//排序主函数
void 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++)
{
Reverse(0,i);
m_ReverseCakeArraySwap[step]=i;
Search(step+1);
Reverse(0,i);
}
}
bool IsSorted(int* pCakeArray,int nCakeCnt)
{
for(int i=1;i<nCakeCnt;i++)
{
if(pCakeArray[i-1]>pCakeArray[i])
{
return false;
}
}
return true;
}
//翻转烙饼信息
void Reverse(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;
}
}
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; //当前搜索次数信息
};
#endif // XINBINGSORT_H_INCLUDED
#include <iostream>
#include "XinbingSort.h"
using namespace std;
#define Cnt 10
int main()
{
CPrefixSorting *cps=new CPrefixSorting;
int p_CakeArray[Cnt]={3,2,1,6,5,4,9,8,7,0};
cps->Run(p_CakeArray,Cnt); //开始计算
cps->Output();
return 0;
}