第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("\n|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
时间: 2024-07-29 13:09:21

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

编程之美笔记--第一章游戏之乐--1.2中国象棋将帅问题

后来一版作者又将最后一句改为:”要求在代码中只能使用一个字节存储变量“. 我的解法: package android.zlb.java; /** * * @author zhanglibin * */ public class TestXiangqi { public static void main(String[] args) { for(int i = 11; i < 100; i++) { if(i / 10 % 3 == 1 && (i % 10 == 1 || i % 1

第1章 游戏之乐——NIM(2)“拈”游戏分析

NIM(2)“拈”游戏分析 1. 问题 有N块石头和两个玩家A和B,玩家A先将石头分成若干堆,然后按照BABA……的顺序不断轮流取石头,能将剩下的石头一次取光的玩家获胜.每次取石头时,每个玩家只能从若干堆石头中任选一堆,取这一堆石头中任意数目(大于1)个石头. 请问:玩家A有必胜策略吗?要怎么分配和取石头才能保证自己有把握取胜? 2. 解法与分析 据说,该游戏起源于中国,英文名字叫做“NIM”,是由广东话“拈”(取物之意)音译而来,经由当年到美洲打工的华人流传出去,这个游戏一个常见的变种是将十二

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

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

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

编程之美书中讲的一摞烙饼的排序一题 这里无法用基本的排序方法对其排序,那么最直接的方法是找出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章 游戏之乐——点游戏

点游戏 1. 问题描述: 给玩家4张牌,每张牌的面值在1-13之间,允许其中有数值相同的牌,采用加.减.乘.除四则运算,允许中间运算存在小数,并且可以使用括号,但每张牌只能用一次.构造表达式,使其结果为24. 输入: n1, n2, n3, n4 (1~13) 输出: 若能得到运算结果为 24, 则输出一个对应的运算表达式 如: 输入: 11, 8, 3, 5 输出: (11-8) * (3*5) = 24 2. [解法一]穷举法 代码如下: 1 package chapter1youxizhi

第1章 游戏之乐——一排石子的游戏

一排石子的游戏 转载:编程之美-MIN(1)一排石头的游戏 1. 原题 1.1 题目 N块石头排成一行,每块石头有各自固定的位置.两个玩家依次取石头,每个玩家每次可以取其中任意一块石头,或者相邻的两块石头,石头在游戏过程中不能移位(即编号不会改变),最后能将剩下的石头一次取光的玩家获胜.这个游戏有必胜策略吗? 1.2 解答 已知:石头数量为N,假设两个玩家分别为玩家A和玩家B,且玩家A先取石头. 当N<=2时,玩家A可以直接取完所有的石头,玩家A有必胜策略. 当N=3时,玩家A先取中间的1个石头

第1章 游戏之乐——连连看游戏设计

连连看游戏设计 连连看是一种很受大家欢迎的小游戏.微软亚洲研究院的实习生们就曾经开发过一个类似的游戏--Microsoft Link-up.    图1-17为Microsoft Link-up的一个截图.如果用户可以把两个同样的图用线(连线拐的弯不能多于两个)连到一起,那么这两个头像就会消掉,当所有的头像全部消掉的时候,游戏成功结束.游戏头像有珍稀动物.京剧脸谱等.Microsoft Link-up还支持用户输入的图像库,微软的同事们曾经把新员工的漫画头像加到这个游戏中,让大家在游戏之余也互相

第1章 游戏之乐——构造数独

构造数独 1. 问题 构造一个9*9的方格矩阵,玩家要在每个方格中,分别填上1至9的任意一个数字,让整个棋盘每一列.每一行以及每一个3*3的小矩阵中的数字都不重复. 2. 求解 用转置的方法生成数独数组,代码如下: 1 package chapter1youxizhileShuDu; 2 3 import java.util.Random; 4 5 /** 6 * 用置换法生成数独矩阵 7 * @author DELL 8 * 9 */ 10 public class ShuDu { 11 pr

第1章 游戏之乐——饮料供货

饮料供货 1. 问题描述 在微软亚洲研究院上班,大家早上来的第一件事是干啥呢?查看邮件?No,是去水房拿饮料:酸奶,豆浆,绿茶.王老吉.咖啡.可口可乐……(当然,还是有很多同事把拿饮料当做第二件事). 管理水房的阿姨们每天都会准备很多的饮料给大家,为了提高服务质量,她们会统计大家对每种饮料的满意度.一段时间后,阿姨们已经有了大批的数据.某天早上,当实习生小飞第一个冲进水房并一次拿了五瓶酸奶.四瓶王老吉.三瓶鲜橙多时,阿姨们逮住了他,要他帮忙. 从阿姨们统计的数据中,小飞可以知道大家对每一种饮料的