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
#include
#include
#include
#include
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.000001
double 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;iW)
{
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;iW)
{
yy[i]-=h*(y[i]+R-W);
}
if((x[i]+R)>L)
{
xx[i]-=h*(x[i]+R-L);
}
}
for(int i=0;iu[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=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>LL[i]>>WW[i];
}
in.close();
out.open("cir.txt",ios::out);
out<<"L\tW\ttotal\t"<
参考资料链接:
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