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

一摞烙饼的排序

  问题:写出一个程序,对于n块大小不一的烙饼,输出最优化的翻饼过程?要保证烙饼按照大小次序摆好——小的在上面,大的在下面。

分析与解法:

用java实现的代码如下:

package chapter1youxizhilePrefixSorting;

import java.util.Scanner;
/**
 * 一摞烙饼的
 * @author DELL
 *
 */
public class PrefixSorting {
    private int[] m_CakeArray;  //烙饼信息数组
    private int m_nCakeCnt;  //烙饼个数
    private int m_nMaxSwap;  //最多交换次数,根据推断,最多为(m_nCakeCnt-1)*2;
    private int[] m_SwapArray;  //交换结果数组
    private int[] m_ReverseCakeArray;    //当前翻转烙饼信息数组
    private int[] m_ReverseCakeArraySwap;  //当前翻转烙饼交换结果数组
    private int m_nSearch;    //当前搜索次数信息
    
    public PrefixSorting(int[] pCakeArray, int nCakeCnt){
        m_nCakeCnt = 0;
        m_nMaxSwap = 0;
        Run(pCakeArray, nCakeCnt);
    }
    
    /**
     * 计算烙饼翻转信息
     * @param pCakeArray  存储烙饼索引数组
     * @param nCakeCnt      烙饼个数
     */
    public void Run(int[] pCakeArray, int nCakeCnt){
        Init(pCakeArray, nCakeCnt);
        m_nSearch = 0;
        Search(0);
    }
    
    //输出烙饼具体翻转次数
    public void Output(){
        System.out.print("交换结果数组为:");
        for(int i=0;i<m_nMaxSwap;i++){
            System.out.print(m_SwapArray[i]+" ");
        }
        System.out.println("
|Search Times| : "+ m_nSearch);
        System.out.println("Total Swap times = "+ m_nMaxSwap);
    }
    
    /**
     * 初始化数组信息
     * @param pCakeArray    存储烙饼索引数组
     * @param nCakeCnt    烙饼个数
     */
    private void Init(int[] pCakeArray, int nCakeCnt){
        if(pCakeArray==null)
            System.out.println("烙饼索引数组为空!");
        if(nCakeCnt <= 0)
            System.out.println("烙饼个数非法!");
        m_nCakeCnt = nCakeCnt;
        //初始化烙饼数组
        m_CakeArray = new int[m_nCakeCnt];
        for(int i=0;i<m_nCakeCnt;i++){
            m_CakeArray[i] = pCakeArray[i];
        }
        //设置最多交换次数信息
        m_nMaxSwap = UpBound(m_nCakeCnt);
        //初始化交换结果数组
        m_SwapArray = new int[m_nMaxSwap];
        //初始化中间交换结果信息
        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];
        
    }
    
    /**
     * 寻找当前翻转的上界
     * @param nCakeCnt 烙饼个数
     * @return
     */
    private int UpBound(int nCakeCnt){
        return (nCakeCnt-1)*2;
    }
    
    /**
     * 寻找当前翻转的下界
     * @param pCakeArray 当前翻转烙饼信息数组
     * @param nCakeCnt    当前烙饼数量
     * @return
     */
    private int LowerBound(int[] pCakeArray, int nCakeCnt){
        int t, ret = 0;
        //根据当前数组的排序信息情况来判断最少需要交换多少次
        for(int i=1;i<nCakeCnt;i++){
            //判断位置相邻的两个烙饼,是否为尺寸排序上相邻的
            t = pCakeArray[i] - pCakeArray[i-1];
            if(Math.abs(t)==1){
                //尺寸排序上相邻不计数
            }else{
                ret++;
            }
        }
        return ret;
    }
    
    //排序的主函数
    private 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++){
            Revert(0,i);
            if(step<m_nMaxSwap)
                m_ReverseCakeArraySwap[step] = i;
            Search(step+1);
            Revert(0,i);
        }
    }
    
    /**
     * 判断是否排好序
     * @param pCakeArray 当前翻转烙饼信息数组
     * @param nCakeCnt    烙饼数量
     * @return
     */
    private boolean IsSorted(int[] pCakeArray, int nCakeCnt){
        for(int i=1;i<nCakeCnt;i++){
            if(pCakeArray[i-1] > pCakeArray[i]){
                return false;
            }
        }
        return true;
    }
    
    /**
     * 翻转烙饼信息
     * @param nBegin 开始位置
     * @param nEnd 结束位置
     */
    private void Revert(int nBegin, int nEnd){
        if(nBegin>=nEnd){
            System.out.println("参数信息有误!开始位置不能大于等于结束位置!");
        }
        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;
        }
    }
    
    public static void main(String[] args) {
        Scanner input = new Scanner(System.in);
        System.out.println("请输入烙饼从上到下的半径,以逗号分隔:");
        String s = input.nextLine();
        String[] ch = s.split(",");
//        int nCakeCnt = 10;
        int nCakeCnt = ch.length;
        int[] pCakeArray = new int[nCakeCnt];
        for(int i=0;i<nCakeCnt;i++){
            pCakeArray[i] = Integer.parseInt(ch[i]);
        }
//        int[] pCakeArray = {3,2,1,6,5,4,9,8,7,0};
        PrefixSorting ps = new PrefixSorting(pCakeArray, nCakeCnt);
        ps.Output();

    }

}

程序运行结果如下:

请输入烙饼从上到下的半径,以逗号分隔:
3,2,1,6,5,4,9,8,7,0
交换结果数组为:4 8 6 8 4 9 
|Search Times| : 148015
Total Swap times = 6
原文地址:https://www.cnblogs.com/gaopeng527/p/4600372.html