编程之美 - 1.3 烙饼排序

问题导读:

假设有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 visited
if ok
for:dfs(x,y,step+1)


bfs()
queue.offer
while(queue.isNotEmpty):
	queue.poll
	if ok
	for:queue.offer

    原文作者:PeersLee
    原文地址: https://blog.csdn.net/PeersLee/article/details/76944496
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞