编程之美

来源:互联网 发布:js input 光标颜色 编辑:程序博客网 时间:2024/06/02 05:18

问题导读:


假设有n块大小不一的烙饼,翻烙饼时只能从最上面的烙饼开始,一次抓住最上面的几块饼,把它们上下颠倒个儿,那么最少要翻多少次,才能够达到最后的大小有序?得到一个解决方案。


解决方案:


package Chapter1;import java.util.*;/*    烙饼排序(寻找最优翻转方案):    1. 将本应该相邻的两个烙饼尽可能的翻转到一起    2. 当前步数 + 估算这次搜索所需要下界步数 < 最多交换次数 */public class Func_1_3_1 {    int []cake_arr; //烙饼信息数组    int cake_cnt; // 烙饼个数    int max_swap; //最多交换次数    int []swap_arr; //烙饼交换结果数组    int []reverse_cake_arr; // 当前翻转 烙饼信息数组    int []reverse_cake_swap_arr; //当前翻转 烙饼交换结果数组    int n_search; // 当前搜索次数    public Func_1_3_1(int []cake_arr, int cake_cnt) {        this.cake_arr = cake_arr;        this.cake_cnt = cake_cnt;        this.max_swap = upperBound(cake_cnt);        this.swap_arr = new int[this.max_swap + 1];        this.reverse_cake_arr = new int[cake_cnt];        for (int i = 0; i<cake_cnt; i++) {            this.reverse_cake_arr[i] = this.cake_arr[i];        }        this.reverse_cake_swap_arr = new int[this.max_swap];        this.n_search = 0;    }    // 得到上界    int upperBound(int cake_cnt) {        /*        1. 最大的在倒数第二位,将它翻到第一位        2. 再将最上的(最大的)翻到最后一位        3. 最后,最小的自然在上,不用翻,        4. 2*(n-1)         */        return (cake_cnt-1) * 2;    }    // 得到下界    int lowerBound(int []cake_arr, int cake_cnt) {        int flag, ret = 0;        for (int i = 1; i < cake_cnt; i++) {            flag = cake_arr[i] - cake_arr[i];            if (flag != 1 && flag != -1) {                ret++;            }        }        return ret;    }    // 翻转烙饼    void reverse(int n_begin, int n_end) {        if (n_begin > n_end)            return;        int i, j;        for(i = n_begin, j = n_end; i<j; i++, j--) {            this.reverse_cake_arr[i] = this.reverse_cake_arr[i] + this.reverse_cake_arr[j] -                    (this.reverse_cake_arr[j] = this.reverse_cake_arr[i]);        }    }    // 判断是否已经排序完成    boolean isSorted(int []cake_arr, int cake_cnt) {        for (int i = 1; i<cake_cnt; i++) {            if (cake_arr[i] < cake_arr[i-1]) {                // 下面的小于上面的,false                return false;            }        }        return true;    }    // 深搜    // 省空间,不一定是最优解    // 重在剪枝    void dfs(int step) {        int n_estimate;        this.n_search++;        n_estimate = lowerBound(this.reverse_cake_arr, this.cake_cnt);        // 步数大于上界        if (step + n_estimate > this.max_swap)            return;        // 如果排序完成        if (isSorted(this.reverse_cake_arr, this.cake_cnt)) {            if (step < this.max_swap) {                this.max_swap = step;                for (int i = 0; i<this.max_swap; i++)                    this.swap_arr[i] = this.reverse_cake_swap_arr[i];            }            return;        }        // 递归进行翻转        for (int i = 1; i<cake_cnt; i++) {            reverse(0, i);            this.reverse_cake_swap_arr[step] = i;            dfs(step + 1);            reverse(0, i);        }    }    // 输出    void outPut() {        System.out.println();        System.out.println(Arrays.toString(this.swap_arr));        System.out.println("搜索次数: " + this.n_search + "\n步数: " + this.max_swap);    }    public static void main(String []args) {        int []arr = {4, 2, 1, 3};        Func_1_3_1 f = new Func_1_3_1(arr, 4);        f.dfs(0);        f.outPut();    }}



参考博文:

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


dfs(x,y,step)if visitedif okfor:dfs(x,y,step+1)bfs()queue.offerwhile(queue.isNotEmpty):queue.pollif okfor:queue.offer



原创粉丝点击