问题描述:如何把任意数量任意尺寸矩形集无重复的放到一个面积最小的封闭矩形中。

算法思想:(为了便于描述,把要找的封闭矩形记为a,封闭矩形的集合记为as,把矩形集合记为rs,n为rs中矩形的个数,把可以插入矩形的位置记为corners)

1.把所有矩形集中的矩形按高度从大到小排序,此时rs[0]高度最大
2.把a初始化为:height = rs[0].height,width = rs[0].width + rs[1].width + ...... + rs[n - 1].width,corners初始化为:坐标顶点
3.把rs[0]放入a中,并把由于rs[0]的插入产生的corner放入corners集合中,删除已经使用的corner,如下图所示:

4.从rs[1]到rs[n - 1],每次插入时选择可以插入的X值最小的corner,插入成功之后,删除已经使用的corner,并且插入新产生的corner,由于a的初始化条件,可以保证rs中的所有矩形都可以插入a中
5.所有矩形插入完成后,对a进行“瘦身”,让a正好包含所有的矩形,并记录此时a的宽度为width,a的面积为area(此时a是所有符合条件的封闭矩形中的‘最狭长’的,令as[0] = a)
6.依次减少a.width,增加a.height,重复3-5,如果a的面积有所减少,则把a插入到as中,直到a.width = rs中最宽矩形的宽度
7.as集合的最后一个元素就是可以包含rs中所有矩形的面积最小的封闭矩形,算法结束

算法实现:

在算法的实现中需要注意的地方:
1.计算由于矩形的插入产生的新的corner(需要考虑很多特殊情况)
2.判断矩形是否可以插入一个corner
3.数据结构的设计

以下程序是算法最核心的方法,插入矩形,并记录新产生的corner

 private boolean putIn(PngRect png){
if(pngs == null){
pngs = new ArrayList<PngRect>();
pngs.add(png);
png.setStartP(new Point(0,0));
if(png.getHeight() < mHeight){
Rect owner = new Rect(0,png.getStopP().getY(),mWidth,mHeight);
Corner corner = new Corner(new Point(0,png.getHeight()),owner);
corners.add(corner);
}
if(png.getWidth() < mWidth){
Rect owner = new Rect(png.getStopP().getX(),0,mWidth,mHeight);
Corner corner = new Corner(new Point(png.getWidth(),0),owner);
corners.add(corner);
}
return true;
}else{
Corner corner;
int x;
int y;
Rect owner;
for(int i = 0; i < corners.size(); ++i){
corner = corners.get(i);
x = corner.getPoint().getX();
y = corner.getPoint().getY();
owner = corner.getRect();
Point startP = corner.getPoint();
int endX = owner.right;
int endY = owner.bottom;
/*
* 可以放进该corner,此处存在覆盖问题,需要判断四条边是否有点在已经被使用,如果是,则返回,试下一个corner
* v0-----v1
* | |
* | a |
* | |
* v2-----v3
* 同时为了防止完全重叠,还需要判断额外一个点,例如图中的a点
*/
if(x + png.getWidth() <= mWidth && y + png.getHeight() <= mHeight){
Point v0 = startP;
Point v1 = new Point(startP.getX() + png.getWidth(),startP.getY());
Point v2 = new Point(startP.getX(),startP.getY() + png.getHeight());
Point v3 = new Point(startP.getX() + png.getWidth(),startP.getY() + png.getHeight());
Point a = new Point(startP.getX() + png.getWidth()/2,startP.getY() + png.getHeight()/2);
if(contains(v0,v1,true) || contains(v1,v3,false) || contains(v2,v3,true) || contains(v0,v2,false) || contains(a)){//有可能正好落在边上
continue;
}
// if(contains(a) ||contains(v0) || contains(v1) || contains(v2) || contains(v3) ){//有可能正好落在边上
// continue;
// }
if(x + png.getWidth() < endX){
corners.add(i + 1,new Corner(new Point(x + png.getWidth(),y),
new Rect(x + png.getWidth(),y,mWidth,mHeight)));//此处owner可能为空
}
if(y + png.getHeight() < endY){
corners.add(i + 1, new Corner(new Point(x,y + png.getHeight()),
new Rect(x,y + png.getHeight(),mWidth,mHeight)));
}
corners.remove(i);
sortCorners();
png.setStartP(corner.getPoint());
pngs.add(png);
return true;
}
}
}
return false;
}

实体类:

Corner

public class Corner {

    //Corner的起始点
private Point point;
//可以填充图片的区域
private Rectangle rect; public Corner(Point point,Rectangle rect)
{
this.point = point;
this.rect = rect;
} public Point getPoint()
{
return point;
} public Rectangle getRect()
{
return rect;
}
}

PngRect

public class PngRect {

    private int mHeight;
private int mWidth;
private Point mStartP;//最左上角的点
private Point mStopP;//最右下角的点
private BufferedImage mBitmap; public PngRect(int width, int height, BufferedImage bitmap)
{
this.mWidth = width;
this.mHeight = height;
this.mBitmap = bitmap;
}
public int getWidth()
{
return this.mWidth;
} public int getHeight()
{
return this.mHeight;
} public void setStartP(Point p)
{
mStartP = p;
mStopP = new Point(p.x + mWidth, p.y + mHeight);
} public Point getStartP()
{
return mStartP;
} public Point getStopP()
{
return mStopP;
} public BufferedImage getBitmap()
{
return mBitmap;
} //判断某个点是否包含在矩形内
public boolean contains(Point p)
{
if (mStartP == null)
{
return false;
}
int x = p.x;
int y = p.y;
if (x > mStartP.getX() && x < mStopP.getX() && y > mStartP.getY() && y < mStopP.getY())
{
return true;
}
return false;
} //把pngs中的图片按高度从大到小排序
public static void sortPngRects(ArrayList<PngRect> pngs)
{
PngRect maxHeightrect;
PngRect tempRect;
PngRect currentRect;
int k;
for (int i = 0; i < pngs.size(); ++i)
{
maxHeightrect = pngs.get(i);
currentRect = pngs.get(i);
k = i;
for (int j = i + 1; j < pngs.size(); ++j)
{
tempRect = pngs.get(j);
if (tempRect.getHeight() > maxHeightrect.getHeight())
{
maxHeightrect = tempRect;
k = j;
}
}
if (k != i)
{
pngs.set(i,maxHeightrect);
pngs.set(k,currentRect);
}
}
}
}

Packing问题的更多相关文章

  1. Bin Packing

    Bin Packing 题目链接:http://acm.hust.edu.cn/vjudge/contest/view.action?cid=85904#problem/F 题目: A set of  ...

  2. UVa 102 - Ecological Bin Packing(规律,统计)

    题目来源:https://uva.onlinejudge.org/index.php?option=com_onlinejudge&Itemid=8&category=3&pa ...

  3. 【Moqui业务逻辑翻译系列】Shipment Receiver Receives Shipment with Packing Slip but no PO

    Shipment Receiver receives shipment. It has invoice tucked into it. Receiver records vendor name, ve ...

  4. UVa - 102 - Ecological Bin Packing

    Background Bin packing, or the placement of objects of certain weights into different bins subject t ...

  5. Uniform and Interpolator Packing的作用

    All of the packing that is done is completely transparent to the user of the OpenGL ES Shading Langu ...

  6. Educational Codeforces Round 34 (Rated for Div. 2) C. Boxes Packing

    C. Boxes Packing time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

  7. USACO 6.2 Packing Rectangles

    Packing RectanglesIOI 95 The six basic layouts of four rectangles Four rectangles are given. Find th ...

  8. Maven使用之packing篇

    项目的打包类型:pom.jar.war 项目中一般使用maven进行模块管理,每个模块下对应都有一个pom文件,pom文件中维护了各模块之间的依赖和继承关系.项目模块化可以将通用的部分抽离出来,方便重 ...

  9. POJ1022 Packing Unit 4D Cubes

    题目来源:http://poj.org/problem?id=1022 题目大意: 有一些4维的单位体积的立方体盒子,每个立方体有8个面.要用一个大的4为盒子将它们包起来,求最小的大盒子体积. 输入: ...

  10. Educational Codeforces Round 34 C. Boxes Packing【模拟/STL-map/俄罗斯套娃】

    C. Boxes Packing time limit per test 1 second memory limit per test 256 megabytes input standard inp ...

随机推荐

  1. 常见的BI软件有哪些_BI工具软件哪个好用

    世界越来越以数据的驱动.数据分析是帮助企业深入了解自身业务表现(例如正在做什么或哪块业务需要注意和改进)的重要元素.为了获得更直观的展现,数据分析软件可帮助公司通过报告.数据可视化.应用程序等从数据中 ...

  2. Android系统编程入门系列之界面Activity响应多元的属性动画

    在响应丝滑动画一篇文章中,分别介绍了作用于普通视图.绘制视图的绘制对象.和界面这三种对象的动画效果,但是都有一些使用的局限性.比如这些动画都只是以屏幕上绘制更新的方式绘制动画,并没有真实改变作用对象的 ...

  3. xmind2020 zen 10.2.1win/mac/linux安装教程

    xmind是一款优秀的思维导图软件,本文教大家如何安装xmind zen 2020 10.2.1版本,解锁使用全部功能,包括去掉xmind zen水印.上传图片等功能,支持windows/mac/li ...

  4. SpringMVC中文乱码踩坑

    问题 使用SpringMVC在返回一个字符串时发生了中文乱码问题.produces属性无效 @RequestMapping(value = "/nihao", produces = ...

  5. JOY靶机

    仅供个人娱乐 靶机信息 下载地址:https://www.vulnhub.com/entry/digitalworldlocal-joy,298/ 一.主机扫描 二.信息收集和漏洞利用     FTP ...

  6. 论文笔记:(CVPR2019)Relation-Shape Convolutional Neural Network for Point Cloud Analysis

    目录 摘要 一.引言 二.相关工作 基于视图和体素的方法 点云上的深度学习 相关性学习 三.形状意识表示学习 3.1关系-形状卷积 建模 经典CNN的局限性 变换:从关系中学习 通道提升映射 3.2性 ...

  7. S01-晓亮的电脑软件安装过程文档 腾讯QQ 595076941 2019年10月

    S01-晓亮的电脑软件安装过程文档 腾讯QQ 595076941 2019年10月 本文档的创建作者的腾讯QQ聊天号码是 595076941 S02-电脑软件安装过程中不要随意关闭窗口除非必需关闭窗口 ...

  8. Netty入门(一):ByteBuf

    网络数据的基本单位总是字节.Java NIO 提供了 ByteBuffer 作为它的字节容器,但是这个类使用起来过于复杂,而且也有些繁琐.Netty 的 ByteBuffer 替代品是 ByteBuf ...

  9. Jmeter分布式压测实战及踩坑处理(含参数化)

    项目中使用Jmeter进行大并发压测时,单机受限内存.CPU.网络IO,会出现服务器压力还没有上 去,但压测服务器由于模拟的压力太大死机的情况.JMeter的集群模式可以让我们将多台机器联合起来 一起 ...

  10. 启动或重启Oracle数据以及监听

    (以下均为命令行形式) 1.切换到oracle数据库用户: su - oracle 2.查看数据库的监听状态: lsnrctl status 3.停止监听: lsnrctl stop 4.登陆到ora ...