多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局之代码解析(一)
介绍 本代码是用C#实现的。在开始代码解析之前,先把要用到的数据贴出来: | 店铺id | 店铺宽度 | 店铺高度 | 入口位置 | | ------ | -------- | -------- | -------- | | 1 | 9 | 6 | (5,6) | | 2 | 5 | 6 | (1,6) | | 3
目录8 个章节
介绍
本代码是用C#实现的。在开始代码解析之前,先把要用到的数据贴出来:
| 店铺id | 店铺宽度 | 店铺高度 | 入口位置 |
|---|---|---|---|
| 1 | 9 | 6 | (5,6) |
| 2 | 5 | 6 | (1,6) |
| 3 | 5 | 6 | (1,6) |
| 4 | 4 | 5 | (1,5) |
| 5 | 4 | 5 | (1,5) |
| 6 | 4 | 5 | (1,5) |
| 7 | 4 | 5 | (1,5) |
| 8 | 4 | 4 | (1,4) |
| 9 | 4 | 4 | (1,4) |
| 10 | 4 | 4 | (1,4) |
| 11 | 4 | 4 | (1,4) |
| 12 | 4 | 4 | (1,4) |
在《开罗拉面店》里,是以左方向为x轴正方向,下方向为y轴正方向的,为了便于咱们计算,咱们可以将值顺时针旋转180°,变成咱们熟悉的坐标系,这样处理完再旋转回去就行。而这里的入口位置,则是相对于店铺左下角(也就是靠近原点的那一个方向)的格子的位置,举例说明:

这个店铺的入口相对于左下角那一格的位置,往左1格,往上4格,所以入口位置是(1,4)。
很容易可以计算出总共有
种排列情况,咱们的任务就是从这些排列情况中找到最优解!任务很艰巨是不是?
店铺类:Store
属性
Store类除了要有id、宽度、高度、入口位置之外,还要记录自己的位置,方便起见,以左下角那一格的坐标作为本店的位置;为了计算方便,还要储存本店扩大一行一列之后得到的矩形。
/// <summary>
/// 拉面店ID
/// </summary>
public int id;
/// <summary>
/// 拉面店左下角坐标
/// </summary>
public Point point;
/// <summary>
/// 拉面店高度
/// </summary>
public int height;
/// <summary>
/// 拉面店宽度
/// </summary>
public int width;
/// <summary>
/// 拉面店门的位置
/// </summary>
public Point door;
/// <summary>
/// 拉面店覆盖区域
/// </summary>
public Rectangle area;
方法
1. 判断店铺之间是否有重叠
这是与约束条件2对应的方法,在用BL算法排兵布阵的时候要判断扩大后的店铺有没有重叠,在铺完扩大后的店铺之后还要判断没扩大的店铺有没有重叠,所以需要写多个成员函数分别判断。
/// <summary>
/// 判断自己与另一个拉面店(扩大后的)是否会重叠
/// </summary>
/// <param name="box">另一个拉面店</param>
/// <returns>若重叠则返回false,不重叠则返回true</returns>
public bool overlap(Store box)
{
if ((point.X + area.Width-1 < box.point.X || point.X > box.point.X + box.area.Width-1) ||
(point.Y + area.Height-1 < box.point.Y || point.Y > box.point.Y + box.area.Height-1))
{
return true;
}
return false;
}
/// <summary>
/// 判断自己与另一个拉面店是否会重叠
/// </summary>
/// <param name="box">另一个拉面店</param>
/// <returns>若重叠则返回false,不重叠则返回true</returns>
public bool overlap_pro(Store box)
{
if ((point.X + width-1 < box.point.X || point.X > box.point.X + box.width-1) ||
(point.Y + height-1 < box.point.Y || point.Y > box.point.Y + box.height-1))
{
return true;
}
return false;
}
/// <summary>
/// 判断本店与其他所有店是否有重叠
/// </summary>
/// <param name="ans">其他所有店</param>
/// <returns>有一个重叠就返回false,全部不重叠返回true</returns>
public bool if_available(List<Store> ans)
{
bool flag = true;
for (int i = 0; i < ans.Count; i++)
{
if (!overlap(ans[i]))
{
flag = false;
break;
}
}
return flag;
}
2. 深复制
在C#里,自定义类作为参数传递的时候默认是传地址的,但是在后面有一些函数在处理的时候是希望传值的(之后会详细说明),所以需要写一个深复制函数。
/// <summary>
/// 深复制
/// </summary>
/// <returns>本店深复制后得到的新店</returns>
public Store Clone()
{
Store ans = new Store(id, new Point(point.X, point.Y), width, height, new Point(door.X, door.Y));
return ans;
}
3. 旋转
对应于约束条件7的成员函数。
/// <summary>
/// 旋转
/// </summary>
public void rotate()
{
int t = height;
height = width;
width = t;
door = new Point(door.Y, door.X);
area = new Rectangle(new Point(0, 0), new Size(width + 1, height + 1));
}
4. BL算法与改进
实现BL算法的第一步是将店铺放到右上角边界的位置,所以需要判断右上角边界那个位置能不能放得下,会不会和其他店铺重叠,如果能放得下的话,就可以开始玩“俄罗斯方块”了。对于BL算法,店铺需要判断能往下多少格,往左多少格;对于BL的改进算法,可以把往下移动和往左移动合并成一个动作。
/// <summary>
/// 判断本店能否在当前位置填充
/// </summary>
/// <param name="W">当前位置横坐标</param>
/// <param name="H">当前位置纵坐标</param>
/// <param name="ans">已填充的拉面店</param>
/// <returns>可以填充返回true,不能填充返回false</returns>
public bool set(int W, int H, List<Store> ans)
{
point.X = W - area.Width;
point.Y = H - area.Height;
return if_available(ans);
}
/// <summary>
/// 向下移动
/// </summary>
/// <param name="store">当前已填充的拉面店</param>
/// <returns>可以移动的最大步数</returns>
public int go_down(List<Store> store)
{
int move = 0;
for (int i = 0; i < store.Count; i++)
{
if (area.Width + point.X > store[i].point.X && point.X < store[i].area.Width + store[i].point.X &&
point.Y >= store[i].point.Y + store[i].area.Height)
{
int l = store[i].point.Y + store[i].area.Height;
if (move < l)
{
move = l;
}
}
}
move = point.Y - move;
point.Y -= move;
return move;
}
/// <summary>
/// 向左移动
/// </summary>
/// <param name="store">当前已填充的拉面店</param>
/// <returns>可以移动的最大步数</returns>
public int go_left(List<Store> store)
{
int move = 0;
for (int i = 0; i < store.Count; i++)
{
if (area.Height + point.Y > store[i].point.Y && point.Y < store[i].area.Height + store[i].point.Y &&
point.X >= store[i].point.X + store[i].area.Width)
{
int l = store[i].point.X + store[i].area.Width;
if (move < l)
{
move = l;
}
}
}
move = point.X - move;
point.X -= move;
return move;
}
/// <summary>
/// BL算法加强版
/// </summary>
/// <param name="store">当前已填充的拉面店</param>
/// <returns>可以移动的最大步数</returns>
public Point BL_plus_move(List<Store> store)
{
int down = 0;
int left = 0;
for (int i = 0; i < store.Count; i++)
{
if (point.X + area.Width > store[i].point.X && point.X < store[i].point.X + store[i].area.Width &&
point.Y >= store[i].point.Y + store[i].area.Height)
{
int l = store[i].point.Y + store[i].area.Height;
if (down < l)
{
down = l;
left = store[i].point.X;
}
}
}
down = point.Y - down;
point.Y -= down;
int move = 0;
for (int i = 0; i < store.Count; i++)
{
if (point.Y + area.Height > store[i].point.Y && point.Y < store[i].point.Y + store[i].area.Height &&
point.X >= store[i].point.X + store[i].area.Width)
{
int l = store[i].point.X + store[i].area.Width;
if (move < l)
{
move = l;
}
}
}
left = Math.Min(point.X + area.Width - left, point.X - move);
point.X -= left;
return new Point(down, left);
}
至此一个简单的Store类就基本实现了,接下来就是个体类的实现。
_EOF_
多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局之代码解析(一)
- 本文作者:
- 程序设计实验室
- 版权声明:
- 本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
相关文章
LittleWhiteOne基本设计
LittleWhite One 魔改chatterbot框架实现的新版小白~ 简介 core:核心框架,魔改版chatterbot corpus:英文和中文训练语料 nltk_data:需要用到的nltk数据集 文本相似度算法 LevenshteinDistance SpacySimilarity JaccardSimilarity Levenshtein Distance算法 中文名:莱文斯坦距
2021-12-18 · 算法/机器学习 · 约 1 分钟
使用分形思想,通过图灵完备的机器赛跑关卡,并获得小机快跑成就
本文将用尽量通俗易懂的语言, 为了解过和没了解过图灵完备和分形的读者讲解用分形思想来通过机器赛跑这一关并达成成就“小机快跑”的思路, 同时也将给出实现该思路的汇编代码。
2024-02-06 · 算法/机器学习 · 约 1 分钟
多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局之代码解析(二)
个体类:Individual 属性 一个个体在遗传算法中最关键的属性是基因编码和性状,为此还需要引出一个原始基因的定义(在敲代码的时候我把这玩意儿叫做基因库,但是后来查资料才发现,基因库是用来储存优秀个体,提高种群质量的,和我这里的作用并不相同,所以作出修正)。原始基因就是题目给定的这12个店铺,而在生成个体的基因的时候就只是单纯的在这条原始基因上进行随机重排序操作和随机旋转操作;性状则是进行这两
2021-12-18 · 算法/机器学习 · 约 1 分钟
多个约束条件下的二维装箱问题——寻找《开罗拉面店》最优布局之代码解析(五)遗传算法解析
前言 遗传算法的一些思路我在开篇有提到一些,这里给出具体过程: 1、生成两个种群,分别使用BL算法和BL_plus算法; 2、开始迭代 3、调用两个种群的update_max()函数更新最优个体 4、如果两个种群中有最优解(也就是12家店铺全部铺上去了),则跳出循环,返回该个体; 5、如果达到迭代次数,则跳出循环,返回两个种群的最优个体; 6、如果达到交换迭代次数,则: 假设种群P1的最优个体适应
2021-12-18 · 算法/机器学习 · 约 1 分钟
讨论
共 0 条加载评论中…