层板等分衣柜问题

524 阅读1分钟

描述:

给定一个高度为 2000mm 的柜子空间,以及 n 个层板距离柜子底部高度,满足移动层板位置,使得层板等分衣柜的空间。计算所有移动层板的顺序。

层板号自下向上依次排列,1、2、... n。层板需要考虑空间位置,不能跨层板移动。

SA}VLCQC_%%ZCFXNA9VDD0L.png

示例 1

输入:n = 3,zs = 50,60,1000

输出:

3 2 1

示例 2

输入:n = 4,zs = 50,600,700,1000

输出:

1,4,3,2

4,1,3,2

4,3,1,2

4,3,2,1

提示 1:1 <= n <= 10

提示 2:输出结果需要按小到大排序

代码实现:

这里直接采用的暴力算法,遍历所有排列组合后再判断

其中,排列组合所有的情况时,若有n块板,则共有n!种情况

若n=9,则遍历时第一个为123456789、123456798、123456879 ......

遍历时,需要计算排列x的下一个排列。

举例:若 x=513987642,

  1. 先自右至左找出排列中第一个比右边数字小的数字3;

  2. 在3后的数字中找出比3大的数中最小的一个4;

  3. 将3与4交换,排列变为 514987632;

  4. 将987632倒转 514236789。

所以513987642的下一个排列是514236789。

遍历过程中直接调用方法进行判断

按排列的顺序遍历每块板,看其移动后会不会越过上下板的边界(第一块板和最后一块要单独拿出来判断,否则会数组越界),若可以移动,则移动该板子(将代表板子位置的数组修改一下),之后判断下一块板子。

若每块板子都能按照该顺序移动,直接控制台打印结果(或者拿个集合接收了最后返回也行)。

public class BaoLi {
    
    public void test(int n, double[] zs) {
        List result = new ArrayList();
        for (int i = 1; i <= n; i++) {
            result.add(i);
        }
        decision(zs,result);
        //sum等于n的阶乘
        int sum=1;
        for(int i=1;i<=n;i++) {
            sum*=i;
        }
        for(int i=1;i<=sum;i++){
            aaa(zs,result);
        }
    }

    //遍历出所有的排列组合
    public void aaa(double[] zs, List result) {
        int n=zs.length;
        for (int i = n-2; i >= 0; i--) {
            if((int)result.get(i)<(int)result.get(i+1)){
                for(int j = n-1; j > i; j--){
                    if((int)result.get(j)>(int)result.get(i)){
                        //交换
                        int a=(int)result.get(i);
                        result.set(i,result.get(j));
                        result.set(j,a);
                        break;
                    }
                }
                //倒转后面的
                for(int j=n-1;j>(n+i)/2;j--){
                    int b=(int)result.get(j);
                    result.set(j,result.get(i+n-j));
                    result.set(i+n-j,b);
                }
                decision(zs,result);
                return;
            }
        }
    }

    //判断该结果是否可行
    public void decision(double[] zs, List result){
        int n = zs.length;
        double h = 2000 / (n + 1);

        double[] zs1=Arrays.copyOf(zs,zs.length);
        for (int k = 1; k <= zs.length; k++) {
            int a = (int)result.get(k-1);

            //判断a板是否能移
            if(a==1){
                if(h * a >= zs1[a]){
                    return;
                }
            }else if(a==n){
                if(h * a <= zs1[a-2]){
                    return;
                }
            }else {
                if(h * a >= zs1[a] || h * a <= zs1[a-2]){
                    return;
                }
            }
            //移动后更改板高度zs1
            zs1[a - 1] = h * a;
        }
        System.out.println(Arrays.toString(result.toArray()));
        return;
    }

}