一、二维矩形排样问题介绍
二维矩形排样问题可以简单理解为:给定一个矩形的材料,需要从上面切割出多个尺寸不同的小矩形,应该如何切割才可以使得材料的利用率最高。
二、方法介绍
小编觉得求解该问题的有以下关键步骤:
1、如何生成小矩形的可放置位置
小编通过实时更新已放小矩形最顶端的红线来生成新的位置,即下图的p1,p2,p3,p4。小编通过链表的方式来存储这些红线,即存储p的x,y坐标和线的长度。
当将一个矩形的左下角放到p4中时,若R4的宽等于l4的长度,或者很接近于l4的长度时(可以用当前所存在小矩形的最小边来判断,若l4的长度减去R4的宽小于最小边,则无需生成线l5),我直接将l4上移到R4顶端;否则,将l4的长等于R4的宽,并生成新的线l5。(注意,这里的小矩形的宽指的是平行于x轴的边的长度)
当选择的位置无法放入任何一个矩形时,我直接将该位置的线直接移动到与相邻两线中较矮的一条线同高的位置,若相邻的线只有一根时,直接移动到高线的高度即可。(注意:移动之后,要将两线合并,生成一根更长的线,即生成一个更宽的位置。)
至于说第一个矩形怎么选择,小编是选择序列的第一个小矩形,这样随着序列的改变,解也会改变。而第一根红线地生成也简单,就是大矩形的最下边。
2、如何从可放置位置中选择一个可放置位置来执行当前的小矩形排布
由于小编的偷懒,便选择了最简单的方式,就是选择y最小的那个位置。
3、如何选择最适合2中所选择的可放置位置的小矩形
这里小编也是选择了最简单的方式,即评分的方式,将每个小矩形放到这个位置中,然后给它打一下分。小编的打分方式为:
(int)((小矩形的宽/位置的长度)*100)/10
对于相同最高分的矩形,小编选择序列中的第一个最高分的矩形。之所以选用上面的打分方式,实际是为了让后面的启发式算法起到更大的作用,否则面对同样的位置,肯定会优先选择宽最接近位置的长度的那个小矩形,这样解的变异能力就变差了。应用小编的方法,即不管是0.96还是0.91,最终的得分都是9分,这样随着序列的变化,解也会相应地变化。当然,这个打分方法只是最简单的一种方式,还有多种方法可以选择。比如一个矩形和空间的匹配度越越高,得分就越高,这样不只是考虑宽,还要考虑高,使用这种打分方法得到的解层与层之间会比较平整。其他的方法小编就不讲了,大家自由去想象。(注意:小矩形是可以旋转的,打分的时候最好旋转一下来打一下分,这样解更好一点)
4、如何更新解
更新解的方法也很简单,只要更新小矩形的序列即可,谈到更新序列这种东西,启发式算法再适合不过,小编使用的是禁忌搜索,当然其他启发式也是完全可以滴,大家可以多用几种方法,然后自己对比一下哈。
算例1排样过程
三、算法测试
测试所用的数据以及排样效果都在下面了,这个效果显示使用的是JavaFx技术,这个技术最适合用来做算法的验证了,解是否正确,画出图一看便知。
算例2排样过程
算例1数据:
400 400(大矩形)
59 115
26 99
68 97
41 63
99 116
21 60
79 118
113 85
86 55
33 114
76 70
27 47
117 40
30 46
60 62
87 55
21 108
60 67
82 93
44 49
84 96
89 34
47 34
94 44
117 80
91 62
112 73
37 92
50 48
113 100
24 55
56 27
103 21
61 24
116 111
51 62
67 76
95 57
113 116
63 49
44 56
52 47
33 66
102 53
117 107
40 106
109 27
79 99
40 82
98 96
105 105
94 31
97 78
50 23
86 22
39 59
54 92
37 67
81 102
58 33
113 88
117 71
20 58
65 63
20 116
114 69
117 29
99 88
90 49
35 80
84 87
79 111
97 25
115 21
82 66
79 84
71 38
68 80
57 82
30 73
102 31
68 42
109 106
40 42
24 71
95 101
39 94
100 108
102 26
57 89
108 54
92 107
38 62
38 32
115 46
68 37
106 84
55 73
48 103
107 64
算例2数据:
DamRectangle bigRectangle = new DamRectangle(1, 500, 900, 1);
List<DamRectangle> smallBigRectangleList = new ArrayList<>();
smallBigRectangleList.add(new DamRectangle(0, 127, 124, 2));
smallBigRectangleList.add(new DamRectangle(1, 131, 234, 1));
smallBigRectangleList.add(new DamRectangle(2, 142, 127, 10));
smallBigRectangleList.add(new DamRectangle(3, 23, 29, 4));
smallBigRectangleList.add(new DamRectangle(4, 43, 27, 2));
smallBigRectangleList.add(new DamRectangle(5, 48, 128, 7));
smallBigRectangleList.add(new DamRectangle(6, 37, 63, 8));
smallBigRectangleList.add(new DamRectangle(7, 45, 40, 6));
smallBigRectangleList.add(new DamRectangle(8, 43, 27, 17));
smallBigRectangleList.add(new DamRectangle(9, 48, 78, 7));
smallBigRectangleList.add(new DamRectangle(10, 37, 35, 4));
smallBigRectangleList.add(new DamRectangle(11, 37, 40, 6));
smallBigRectangleList.add(new DamRectangle(12, 43, 43, 7));
smallBigRectangleList.add(new DamRectangle(13, 48, 27, 16));
smallBigRectangleList.add(new DamRectangle(14, 37, 123, 8));
smallBigRectangleList.add(new DamRectangle(15, 42, 40, 10));