一块长方形的大布料截取若干个小的长方形布料,小长方形布料不能旋转,怎么使组成的不规则图形的长度最小?

大的长方体布料的的宽是固定不变的,长度不限,小的长方体布料不能旋转,长宽高固定,但不一致,请问怎么排版,剩余的大的长方体能够截取的新的长方体最大。

举个例子:7个小长方形填充到大的长方形里面,有多种排列方法,举例 a,b两种,希望得到B这种排列方式,这样截取的布料的长度最小

img

网上找到一个大佬相似的回答,但是不知道怎么转成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);
    }
}

例子也是维基百科上的:

img

输出结果:
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;
    }
}