Java学习者论坛

 找回密码
 立即注册

QQ登录

只需一步,快速开始

手机号码,快捷登录

恭喜Java学习者论坛(https://www.javaxxz.com)已经为数万Java学习者服务超过8年了!积累会员资料超过10000G+
成为本站VIP会员,下载本站10000G+会员资源,购买链接:点击进入购买VIP会员
JAVA高级面试进阶视频教程Java架构师系统进阶VIP课程

分布式高可用全栈开发微服务教程

Go语言视频零基础入门到精通

Java架构师3期(课件+源码)

Java开发全终端实战租房项目视频教程

SpringBoot2.X入门到高级使用教程

大数据培训第六期全套视频教程

深度学习(CNN RNN GAN)算法原理

Java亿级流量电商系统视频教程

互联网架构师视频教程

年薪50万Spark2.0从入门到精通

年薪50万!人工智能学习路线教程

年薪50万!大数据从入门到精通学习路线年薪50万!机器学习入门到精通视频教程
仿小米商城类app和小程序视频教程深度学习数据分析基础到实战最新黑马javaEE2.1就业课程从 0到JVM实战高手教程 MySQL入门到精通教程
查看: 758|回复: 0

解决Rectangle Packing问题-  Android学习

[复制链接]

该用户从未签到

发表于 2011-10-24 14:48:53 | 显示全部楼层 |阅读模式
问题描述:如何把任意数量任意尺寸矩形集无重复的放到一个面积最小的封闭矩形中。
算法思想:(为了便于描述,把要找的封闭矩形记为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&ltngRect>();

                        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;

        }
复制代码算法实现的效果如下所示:


如果矩形集个数比较多,算法执行时间较长,应该可以有优化的地方。
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

QQ|手机版|Java学习者论坛 ( 声明:本站资料整理自互联网,用于Java学习者交流学习使用,对资料版权不负任何法律责任,若有侵权请及时联系客服屏蔽删除 )

GMT+8, 2025-1-11 11:47 , Processed in 0.368694 second(s), 34 queries .

Powered by Discuz! X3.4

© 2001-2017 Comsenz Inc.

快速回复 返回顶部 返回列表