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

算法思想:(为了便于描述,把要找的封闭矩形记为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. python基础问题

    包安装相关问:如何安装Python三方包?在命令行如何检查一个包是否已安装?答:安装用pip install 卸载用 pip uninstall 直接import 这个包问:环境变量PATH的作用是什 ...

  2. 第十六篇 -- QListWidget与QToolButton(功能)

    效果图: 添加的部分,就是对几个action绑定了槽函数,完成相应的功能. listWidget操作的都是item,添加一个item,删除一个item,插入一个item等等.那么只需要知道item的几 ...

  3. 【Azure API 管理】在APIM中使用客户端证书验证API的请求,但是一直提示错误"No client certificate received."

    API 管理 (APIM) 是一种为现有后端服务创建一致且现代化的 API 网关的方法. 问题描述 在设置了APIM客户端证书,用户保护后端API,让请求更安全. 但是,最近发现使用客户端证书的API ...

  4. Python将字符串转化为对应类名的两种方法

    way first: 1 from django.utils.module_loading import import_string 2 ValidationError = import_string ...

  5. 【阅读笔记】Java核心技术卷一 #0

    这是一篇备忘性质的读书笔记,仅记录个人觉得有用的知识点 本文作为一个目录索引,部分章节跳过 吐槽:此书中文翻译有不少地方不太通顺,这种情况我要把英文版对应的部分也读一遍才能明白(说实话,英文里的从句表 ...

  6. solr(CVE-2019-17558)远程命令执行

    影响版本 Apache Solr 5.x到8.2.0版本 测试 https://github.com/jas502n/CVE-2019-0193

  7. centos 7 网络静态IP配置文件

    TYPE=EthernetPROXY_METHOD=noneBROWSER_ONLY=noBOOTPROTO=staticIPADDR=10.86.128.160GETWAY=10.86.128.1P ...

  8. Python - 函数实战

    前言 参考的是慕课网提供的实战,自己编码 http://www.imooc.com/wiki/pythonlesson1/function2.html 什么是模块化程序设计 在进行程序设计时将一个大程 ...

  9. Axure RP 9 安装

    安装好的样子 官方安装包下载地址(速度较慢) 下载Axure RP 9 MAC版:https://axure.cachefly.net/AxureRP-Setup.dmg 下载Axure RP 9 P ...

  10. awk-06-常用内置函数

    常用内置函数 示例 1.int 2.sqrt 3.rand rand()并不是每次运行都会产生一个随机数,会一直保持不变 所以需要srand() 函数一起 但是还是有很大的几率会生成一样 4.asor ...