Packing问题,是一类组合优化问题,研究的是把一组较小的图形相互间无嵌入的放入较大的图形,其最终目标是寻求最优(放入最多的小图形)的放置方式。有效地求解此类问题,可以较好地利用资源、减少浪费,这对实际的生产领域,如物体的运输、堆放以及原料的下料等领域,具有不可估量的经济效益。

早在10世纪初期,就有数学家们对此类问题进行了探索。但是由于Packing问题通常都是NP难度的,所以当问题规模增大到一定的程度时,目前尚未有任何算法可以保证能够在有效地时间内求解出最优解。但随着实际生产的迫切需求,研究者们提出了许多有效地搜索策略,采用启发式算法对此类问题进行了快速的近似求解。

本文所涉及的仅仅是放入大矩形的圆形Packing问题,即求解把一组较小的圆形放入较大的矩形的最优解问题。采用的算法,主要参考了国内学者黄文奇教授等提出的拟人拟物策略,参考的文献链接在本文的末尾标注,感兴趣的同学可以深入研读。可以用拟物策略、最都下降算法、拟人策略来概括。我大致简略的进行了拜读,感觉黄文奇教授提出的这个拟人拟物思想挺有意思,对我们的学习工作也很有启发意义,所以建议有时间感兴趣的同学真的可以读一下,这里只做大体的介绍。

算法思想:

首先,给出k个小圆,尝试将它们放入大的矩形当中。若成功,则继续尝试将k+1个小圆放入其中;否则,算法结束,k就是最优解。下面详细叙述怎样进行有效地尝试以期能够把这k个小圆放入到大矩形当中。

设矩形的左下角为坐标系的原点(0,0),假若能够把这k个小圆放入其中,则应满足如下条件:

其中R为小圆的半径长(这里为了简单,取了相同的小圆,如不同,只需半径变化,道理相同),xi、yi分别是第i个小圆的横纵坐标,L为大矩形的长,W为大矩形的宽。(下同)

为寻找满足条件的解,先随机的把k个圆的圆心放入到大矩形当中,然后定义与圆形间以及圆形与边界间的嵌入深度相关的“势能”。

第i个与第j个圆之间的势能:

第i个圆与矩形的四条边之间的势能:

最后,定义整个系统的势能值:

很容易理解,寻找放置k个圆的过程,即是寻找U(X)为0的过程。为了快速寻找到满足条件的解,这里选用最陡下降法进行下一轮圆心X,Y的选择。

算法描述:

最后,根据上面的介绍,给出具体的C++代码实现:

#include<iostream>
#include<fstream>
#include<ctime>
#include<stdlib.h>
#include<math.h>
using namespace std;ifstream in;
ofstream out;#define TURN 1000000000
#define PI 3.1415926
#define r 0.8
#define e1 0.000001
#define e2 0.000001double WW[100];
double LL[100];
int LEN;
double W;
double L;
double R=sqrt(1/PI);double x[100];
double y[100];
double u[100];
double U;
int m;int t=0,k0=0;
double h=1;
void newposk(int);
void position()
{for(int i=0;i<m;i++){x[i]=(W*rand()/(RAND_MAX+1.0));y[i]=(L*rand()/(RAND_MAX+1.0));}
}
double ux()
{U=0;for(int i=0;i<m;i++){u[i]=0;for(int j=i+1;j<m;j++){double dis=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));if(dis<(2*R)){u[i]+=2*R-dis;}}if(y[i]<R){u[i]+=R-y[i];}if(x[i]<R){u[i]+=R-x[i];}if((y[i]+R)>W){u[i]+=y[i]+R-W;}if((x[i]+R)>L){u[i]+=x[i]+R-L;}U+=u[i];}return U;
}
void newpos()
{double xx[100],yy[100];for(int i=0;i<m;i++){xx[i]=0;yy[i]=0;for(int j=0;j!=i&&j<m;j++){double dis=sqrt((x[i]-x[j])*(x[i]-x[j])+(y[i]-y[j])*(y[i]-y[j]));if(dis<e1){newposk(j);j--;break;}if(dis<(2*R)){xx[i]+=h*(2*R-dis)*(x[i]-x[j])/dis;yy[i]+=h*(2*R-dis)*(y[i]-y[j])/dis;}}if(y[i]<R){yy[i]+=h*(R-y[i]);}if(x[i]<R){xx[i]+=h*(R-x[i]);}if((y[i]+R)>W){yy[i]-=h*(y[i]+R-W);}if((x[i]+R)>L){xx[i]-=h*(x[i]+R-L);}}for(int i=0;i<m;i++){x[i]+=xx[i];y[i]+=yy[i];}
}
int maxenergy()
{int energy=0;for(int i=1;i<m;i++){if(u[energy]<u[i]){energy=i;}}return energy;
}
int minenergy()
{int energy=0;for(int i=1;i<m;i++){if(u[energy]>u[i]){energy=i;}}return energy;
}
void newposk(int k)
{x[k]=(W*rand()/(RAND_MAX+1.0));y[k]=(L*rand()/(RAND_MAX+1.0));
}
int step()
{int turn=0;while(turn<TURN){position();t=0;k0=0;h=1;double x0=ux();if(x0<e2){return 1;}bool flag=true;while(flag&&turn<TURN){flag=false;newpos();double x1=ux();if(x1<e2){return 1;}if(x1>=x0){h=r*h;}x0=x1;if(h>=e1){flag=true;int k=maxenergy();if(k==k0){t=t+1;}if(t<1){newposk(k);h=1;k0=k;}else if(t==1){k=minenergy();newposk(k);h=1;k0=0;t=0;}}turn++;}}return 0;
}
int main()
{srand((unsigned)time(0));in.open("LW.txt",ios::in);in>>LEN;for(int i=0;i<LEN;i++){in>>LL[i]>>WW[i];}in.close();out.open("cir.txt",ios::out);out<<"L\tW\ttotal\t"<<endl;for(int i=0;i<LEN;i++){L=LL[i];W=WW[i];m=1;while(step()){m++;}out<<L<<"\t"<<W<<"\t"<<m<<endl;}return 0;
}

不过,遗憾的是,虽然几经修改,但是这个代码的实现效果距离最优解仍然具有差距...所以在这里也请求大牛们如果发现代码实现过程中有什么问题或者可以改进的方向,欢迎批评指正,会非常感谢您的不吝赐教!!!

参考资料链接:

http://www.cnki.net/KCMS/detail/detail.aspx?QueryID=26&CurRec=1&recid=&filename=2003112288.nh&dbname=CDFD2004&dbcode=CDFD&pr=&urlid=&yx=

http://www.cnki.net/KCMS/detail/detail.aspx?QueryID=6&CurRec=1&recid=&filename=JSGG200335009&dbname=CJFD2003&dbcode=CJFQ&pr=&urlid=&yx=

http://www.cnki.net/KCMS/detail/detail.aspx?QueryID=10&CurRec=8&recid=&filename=JFYZ200204004&dbname=cjfd2002&dbcode=CJFQ&pr=&urlid=&yx=

不方便中国知网下载的同学,可以参照下面链接下载:

http://download.csdn.net/detail/smarteryu/5097679

http://download.csdn.net/detail/smarteryu/5097680

把圆形放入矩形的Packing问题相关推荐

  1. 【Java 并发编程】线程池机制 ( 线程池执行任务细节分析 | 线程池执行 execute 源码分析 | 先创建核心线程 | 再放入阻塞队列 | 最后创建非核心线程 )

    文章目录 一.线程池执行任务细节分析 二.线程池执行 execute 源码分析 一.线程池执行任务细节分析 线程池执行细节分析 : 核心线程数 101010 , 最大小成熟 202020 , 非核心线 ...

  2. 8个球放入3个盒子方式_8种土豆做法,好吃到根本停不下来!

    石锅土豆鸡块 鸡腿3,土豆1,青椒2 洋葱一半,辣椒10g,肉桂5g 八角2,生姜10克,大蒜15g 1.将鸡腿洗净切成大块,切成薄片,切青椒,切洋葱片,姜片和蒜片去皮. 2.在锅里加油,加热.加入马 ...

  3. Xilinx FPGA 将寄存器放入IOB中

    xilinx FPGA的资源一般指IOB,CLB,BRAM,DCM,DSP五种资源.其中IOB就是input/output block,完成不同电气特性下对输入输出信号的的驱动和匹配要求. IOB的作 ...

  4. sketch放入app组件_Sketch App 3中的基本图像编辑入门

    sketch放入app组件 I've been talking a lot about Sketch App lately. I never forget to mention that it's a ...

  5. AMOS分析技术:斜交验证性因子分析;介绍如何整理出能够放入论文的模型信效度结果

    基础准备 上一篇文章我们介绍了验证性因子分析的概念和分析逻辑,以及通过验证性因子分析可以直接或间接的得到哪些问卷数据的信度与效度指标,大家可以点击下方的文章名称回顾: AMOS分析技术:验证性因子分析 ...

  6. jpg图片无损放入PDF的程序,PDF文件格式分析,图像表达方式

    wxleasyland@139.com 用打印的方式,一般是将JPG解码后的数据发给打印机,而不是JPG原始数据,所以PDF打印机会重新压缩. 不对JPG图像进行解压,直接将JPG图像传送到虚拟打印机 ...

  7. 汇编语言中将数据、代码、栈放入不同的段

    数据.代码.栈放入不同的段 在学习汇编语言,将数据.代码.栈放入不同的段.参考王爽老师的<汇编语言>第四版,对P133的汇编代码,进行了个人理解标注.仅供参考,存在错误之处,请大家斧正. ...

  8. 【Qt】QStackedWidget:将多个窗口控件放入堆中,每次只显示一个窗口控件

    1.简介 QStackedWidget可以容纳多个窗口控件,每次只显示其中一个.例如:登录页面.各种功能页面等不同时显示的窗口,可以放入QStackedWidget中. 2.demo // 创建三个页 ...

  9. 将Bean放入Spring容器中的五种方式

    欢迎关注方志朋的博客,回复"666"获面试宝典 来源:blog.csdn.net/weixin_43741092/ article/details/120176466 将bean放 ...

最新文章

  1. python如何调用参数配置文件_python参数设置
  2. java 参数 exception_java – 在异常的参数中使用泛型
  3. go mongodb排序查询_【赵强老师】MongoDB中的索引(下)
  4. 针对C++和Delphi的LiveBindings一瞥
  5. matalotlib(2)
  6. 消费者驱动的微服务契约测试套件Spring Cloud Contract
  7. bash --config command not found 报错
  8. mysql查看触发器_在mysql中如何查看和修改触发器的代码?请问各位大师,小弟先谢谢了!!!!!!!!!...
  9. 爆料称配备更大屏幕尺寸的Apple Silicon版iMac仍在研发中
  10. [MySQL] - MySQL的Grant命令
  11. iweboffice2015库文件WebOffice.js中新增删除两个书签之间的内容实现
  12. PhD Debate-11 预告 | 回顾与展望神经网络的后门攻击与防御
  13. 网站被封申诉通道方式方法
  14. 浏览器标准模式和怪异模式之间的区别是什么?
  15. api多版本方案(URL)
  16. 消极和积极的道德--给亲爱的安德烈
  17. shell编程——select语句
  18. java中任何变量都可以被赋值为null,java中当给一个对象赋值为null时发生了什么...
  19. 水果店圈子:水果店水果都去哪进货,水果店进货怎么找货源
  20. 微信小程序生成二维码方法1

热门文章

  1. Android 蓝牙开发——PBAP协议(十)
  2. 家庭宽带市场竞争分析
  3. matlab中s_cplot,matlab系统模型建立和动态特性研究分析实验.docx
  4. java pdf加水印 性能_利用java批量给pdf加水印的方法示例
  5. 转载一篇关于颜色的英文名,算比较全的了!说不定以后用得上!
  6. 随笔:教育、兴趣 与 职业
  7. 华兴数控g71外圆循环编程_数控G71内外圆粗车循环指令教案
  8. 通用vue组件化搜索组件页面
  9. 第一章 初识OpenHarmony
  10. 揭开人工智能的神秘面纱