大的长方体布料的的宽是固定不变的,长度不限,小的长方体布料不能旋转,长宽高固定,但不一致,请问怎么排版,剩余的大的长方体能够截取的新的长方体最大。
举个例子:7个小长方形填充到大的长方形里面,有多种排列方法,举例 a,b两种,希望得到B这种排列方式,这样截取的布料的长度最小
网上找到一个大佬相似的回答,但是不知道怎么转成java或者js代码,请大家帮我看下
将N个大小不等的矩形不重叠地拼在一个指定的大矩形里(大矩形长宽固定),求使占用大矩形区域最小的算法
解题思路如下:
小矩形长为a1,a2……an
宽为b1,b2,……bn
所有常量(长和宽)放到一个数列A中,按大小排序;
设置大矩形图像起始点O1(0,0)
if A不为空,then 循环
{
如其中(A中元素)最大的是bi,从数列中删除bi和ai;
O1点删除bi*ai区域(矩阵数值归零),剩余部分生成两个或多个矩形。长宽分别为c1,c2……d1,d2……放到数列B中,按大小排序;
找出B中最小值ci加入数列A排序。O定为ci对应点。
在A中取小于ci的最大常量;从A删除ci;
}
输出矩阵M
这个问题叫Strip packing,维基百科上介绍了几种算法。下面的实现是FFDH。
import java.util.*;
public class StripPacking {
static class Rectangle {
int w;
int h;
public Rectangle(int w, int h)
{
this.w = w;
this.h = h;
}
}
static class Level {
public Level(int stripW)
{
this.stripW = stripW;
}
final int stripW;
int usedW = 0;
ArrayList<Rectangle> rects = new ArrayList<Rectangle>();
public boolean TryAdd(Rectangle r)
{
if(usedW + r.w <= stripW) {
rects.add(r);
usedW += r.w;
return true;
}
return false;
}
public String toString() {
var s = new StringBuilder("Level height ");
s.append(rects.get(0).h).append(", rectangles: ");
for(var r : rects) {
s.append("(w:").append(r.w).append(", h:").append(r.h).append(") ");
}
return s.toString();
}
}
public static void FFDH(int stripWidth, Rectangle[] rects)
{
// Sort by h from big to small
Arrays.sort(rects, (a, b) -> Integer.compare(b.h, a.h));
var levels = new ArrayList<Level>();
for(var r : rects) {
if(r.w > stripWidth) {
continue;
}
boolean added = false;
for(var level : levels) {
if(level.TryAdd(r)) {
added = true;
break;
}
}
if(!added) {
// add a new level
var level = new Level(stripWidth);
level.TryAdd(r);
levels.add(level);
}
}
int totalH = 0;
for(var level : levels) {
totalH += level.rects.get(0).h;
System.out.println(level);
}
System.out.println("total height used " + totalH);
}
public static void main(String[] args)
{
var rects = new Rectangle[] {
new Rectangle(6, 8),
new Rectangle(5, 7),
new Rectangle(4, 6),
new Rectangle(7, 5),
new Rectangle(3, 4),
new Rectangle(4, 3),
new Rectangle(6, 2),
};
FFDH(18, rects);
}
}
例子也是维基百科上的:
输出结果:
Level height 8, rectangles: (w:6, h:8) (w:5, h:7) (w:4, h:6) (w:3, h:4)
Level height 5, rectangles: (w:7, h:5) (w:4, h:3) (w:6, h:2)
total height used 13
参考代码
import java.util.Arrays;
public class Main {
static class Rectangle {
int width;
int length;
public Rectangle(int width, int length) {
this.width = width;
this.length = length;
}
}
public static void main(String[] args) {
Rectangle[] rectangles = new Rectangle[] {
new Rectangle(3, 5),
new Rectangle(2, 3),
new Rectangle(1, 4),
new Rectangle(4, 5),
new Rectangle(3, 2)
};
int bigWidth = 5;
Arrays.sort(rectangles, (a, b) -> {
return b.length - a.length;
});
int remainingLength = 0;
for (int i = 0; i < rectangles.length; i++) {
if (rectangles[i].width > bigWidth) {
continue;
}
if (rectangles[i].width <= bigWidth) {
bigWidth -= rectangles[i].width;
remainingLength += rectangles[i].length;
}
}
System.out.println("剩余长度: " + remainingLength);
}
}
以上是一种算法的描述,该算法的主要思路是:将所有的小长方体的长宽放入一个数列中,对数列进行排序;循环处理数列中的元素,依次构建矩阵,直至数列中元素处理完毕。
这只是一种思路,如果需要编写代码实现该算法,还需要结合具体需求进行代码设计与实现。
这是一种基于分治算法的思想,用于确定最佳的小长方形的排列方式,以使剩余的长方形长度最短。可以通过在每一次循环中删除长度最长的小长方形,然后将剩余部分分成两个或多个小长方形,再将它们加入长度排序的数列中来实现。
为了方便实现,这里给出一份 Java 代码,可以作为实现思路的参考:
import java.util.ArrayList;
import java.util.Collections;
public class PackRectangles {
private ArrayList<Integer> A;
private int width;
private int height;
public PackRectangles(int[] a, int width) {
this.A = new ArrayList<>();
for (int i : a) {
A.add(i);
}
this.width = width;
Collections.sort(A);
}
public int pack() {
height = 0;
while (!A.isEmpty()) {
int bi = A.remove(A.size() - 1);
int ai = A.remove(A.size() - 1);
height += bi;
ArrayList<Integer> B = new ArrayList<>();
for (int i : A) {
if (i <= ai) {
B.add(i);
}
}
A.removeAll(B);
for (int ci : B) {
A.add(ai - ci);
}
}
return height;
}
}