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

算法思想:(为了便于描述,把要找的封闭矩形记为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中浮点数比较判断!为什么不能用==

    问题:浮点数比较为什么不能用==来写? 答:计算机里面的数字是由二进制保存的,在计算机内部有些数字不能准确的保存,于是就保存了一个最靠近的数字. 计算机表示浮点数(float或double类型)都有一 ...

  2. Python自动化测试面试题-Redis篇

    目录 Python自动化测试面试题-经验篇 Python自动化测试面试题-用例设计篇 Python自动化测试面试题-Linux篇 Python自动化测试面试题-MySQL篇 Python自动化测试面试 ...

  3. C++第三十六篇 -- 为第一个驱动程序进行调试

    工具是VMware12+Win10+VS2017+WDK1809 https://blog.csdn.net/qq_21763381/article/details/83242916 首先分清楚主计算 ...

  4. 我眼中的java线程池实现原理

    最近在看java线程池实现方面的源码,在此做个小结,因为网上关于线程池源码分析的博客挺多的,我也不打算重复造轮子啦,仅仅用纯语言描述的方式做做总结啦! 个人认为要想理解清楚java线程池实现原理,明白 ...

  5. rsync(873)未授权访问

    cd vulhub-master/rsync/common docker -composeup -d 检测 1.列出目标服务器的同步目录 rsync 192.168.244.129:: 2.查看模块文 ...

  6. php预定义常量运用

    当前url 'http://'.$_SERVER['HTTP_HOST'].$_SERVER['REQUEST_URI']; 当前文件路径 dirname(__FILE__)header(" ...

  7. Activiti7 结束/终止流程

    1.  结束/终止 正在运行的流程实例 思路:跟回退一样的思路一样,直接从当前节点跳到结束节点(EndEvent) /** * 结束任务 * @param taskId 当前任务ID */ publi ...

  8. template.js模板工具案例

    案例一 1 <!DOCTYPE html> 2 <html lang="en"> 3 <head> 4 <meta charset=&qu ...

  9. C++ 1 (只在源文件)//点和圆的关系 //设计一个圆形类 和一个点类 计算点和圆的关系 //点到圆心的距离 == 半径 点在圆上 //点到圆心的距离 > 半径 点在圆外 //点到圆心的距离 < 半径 点在圆内 //点到圆心的距离 获取 ....... (x1 -x2)^2 + (y1-y2)^2 开根号 和半径对比 // 计算 可以 两边同时 平方

    1 //点和圆的关系 2 //设计一个圆形类 和一个点类 计算点和圆的关系 3 //点到圆心的距离 == 半径 点在圆上 4 //点到圆心的距离 > 半径 点在圆外 5 //点到圆心的距离 &l ...

  10. 中高级Android大厂面试秘籍,为你保驾护航金三银四,直通大厂(上)

    前言 当下,正面临着近几年来的最严重的互联网寒冬,听得最多的一句话便是:相见于江湖~.缩减HC.裁员不绝于耳,大家都是人心惶惶,年前如此,年后想必肯定又是一场更为惨烈的江湖厮杀.但博主始终相信,寒冬之 ...