描述:
给定一个高度为 2000mm 的柜子空间,以及 n 个层板距离柜子底部高度,满足移动层板位置,使得层板等分衣柜的空间。计算所有移动层板的顺序。
层板号自下向上依次排列,1、2、... n。层板需要考虑空间位置,不能跨层板移动。
示例 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,
-
先自右至左找出排列中第一个比右边数字小的数字3;
-
在3后的数字中找出比3大的数中最小的一个4;
-
将3与4交换,排列变为 514987632;
-
将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;
}
}