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

算法思想:(为了便于描述,把要找的封闭矩形记为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. Aria2 任意文件写入

    访问aria2,发现服务已启动并且返回404页面 打开http://binux.github.io/yaaw/demo/#打开yaaw,点击配置按钮,填入运行aria2的目标域名:http://you ...

  2. 随处可编辑的编辑器之神VIM

    据说这世界上只有三种编辑器:Vim,Emacs 和 其他编辑器,其中 Vim 被称作编辑器之神,Emacs 被称作神的编辑器,当然,其他编辑器永远只能是其他编辑器. 拿一位 网友的话 来说,VIM 的 ...

  3. Spring Cloud分区发布实践(1) 环境准备

    最近研究了一下Spring Cloud里面的灰度发布, 看到各种各样的使用方式, 真是纷繁复杂, 眼花缭乱, 不同的场景需要不同的解决思路. 那我们也来实践一下最简单的场景: 区域划分: 服务分为be ...

  4. js控制单选按钮选中某一项

    <!DOCTYPE html><html> <head> <meta charset="utf-8"> <title>& ...

  5. 使用scrapy搭建大型爬虫系统

    最近新项目准备启动,在开始前内容.词库这些都需要提前做好准备,所以就有了这篇文章.在开始动手,看了下行业核心词排在首页的站,发现内容都多得不要不要的,各种乱七八糟的频道.页面模板,心想,如果每个网站. ...

  6. Vulhub-DC-2靶场

    Vulhub-DC-2靶场 前言 最近一直忙于学习代码审计和内网渗透,所以靶场这方面的文章一直未更新,但是计划是更新完DC系列靶场的,这个不会鸽. DC-2的靶场是很简单的一共5个flag. 正文 f ...

  7. 建立局域网内使用的CentOS7-OpenStack源

    by 无若 1. 先建立局域网内使用的CentOS7源 这个参看 http://www.cnblogs.com/gleaners/p/5735472.html 2. 抓取所有OpenStack的包,文 ...

  8. Linux下使用pure-ftpd建立匿名ftp访问

    by 无若 (一)ubuntu14.04下使用pure-ftpd建立匿名ftp访问 1.安装apt-get install pure-ftpd 2.修改配置nano /etc/pure-ftpd/co ...

  9. ES6继承和ES5继承是完全一样的么?

    继承方式 ES5 prototype 继承 通过原型链(构造函数 + [[prototype]])指向实现继承. (备注:后续__proto__我都会写成[[prototype]]这种形式) 子类的 ...

  10. SpringBoot 整合缓存Cacheable实战详细使用

    前言 我知道在接口api项目中,频繁的调用接口获取数据,查询数据库是非常耗费资源的,于是就有了缓存技术,可以把一些不常更新,或者经常使用的数据,缓存起来,然后下次再请求时候,就直接从缓存中获取,不需要 ...