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

算法思想:(为了便于描述,把要找的封闭矩形记为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. C++第三十七篇 -- 调试驱动程序

    上一篇写的KMDF程序是通过串口进行配置的,那么我们在VS中Attach to process外,可以直接用Winbdg进行调试,winbdg.exe所在路径为C:\Program Files (x8 ...

  2. 记录一个SQL语句 case select 1

    select Code, CodeName, CodeAlias, ComCode, OtherSign from ldcode where codetype = 'edorapptype' and ...

  3. Magento 2.2 SQL注入漏洞

    影响版本 2.2.* poc地址  https://github.com/ambionics/magento-exploits python3 magento-sqli.py http://192.1 ...

  4. 预训练语言模型的前世今生 - 从Word Embedding到BERT

    预训练语言模型的前世今生 - 从Word Embedding到BERT 本篇文章共 24619 个词,一个字一个字手码的不容易,转载请标明出处:预训练语言模型的前世今生 - 从Word Embeddi ...

  5. 方法对了,你做1年Android开发能顶别人做10年

    前几天后台有读者问我这样的问题.他在一家互联网公司工作3年了,每天都很忙,事情又多又杂. 本想着学习多一些东西也不是坏事,可到头来一无所获,什么都没学会,满腔的热情也被消磨得差不多. 三天两头动辞职的 ...

  6. Netty:简单使用

    Netty是什么东西 Netty是一个封装很好的异步事件驱动框架,让我们快速的部署服务端和客户端的网络应用,进行异步IO通信. 1.什么是IO通信IO就是input 和 output,是一种在两台主机 ...

  7. HTTP和HTTPS是什么 二者区别是什么

    HTTP简介 HTTP(超文本传输协议)是网络上最为广泛的传输协议,被用于在web浏览器和网站服务器之间的传输协议.HTTP是一个简单的请求-响应协议,它通常运行在TCP之上.它指定了客户端可能发送给 ...

  8. cobaltstrike 框架简述

    关于cobalt strike,火起来也有好几年了,首先感谢大佬们慷慨相助愿意在网上分享和翻译相关资料,让这么好的渗透测试框架工具被更多人知道 那就来整理一下在使用这个框架的过程中我认为需要了解的小知 ...

  9. java对xml节点属性的增删改查实现方法

    package vastsum; import java.io.File; import java.io.FileWriter; import java.util.Iterator; import o ...

  10. noip42

    T1 朴素dp很好想,设 \(dp_{u,0/1}\) ,表示以 \(u\) 为根的子树,选/不选 \(u\) 所产生的最大贡献. 转移方程则有, \[dp_{u,0} = \prod_{v\in s ...