编程之美之馅饼排序

如何找到这个问题的最优解呢?

每次都把当前最大的和上面的馅饼一起翻转,这样最多需要翻转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("
  |Search Times| :%d
",m_nSearch);
        printf("Total Swap times=%d
",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;
}
原文地址:https://www.cnblogs.com/fistao/p/3219999.html