关于矩形排样问题(三)

下面只给出核心部分的实现(程序写得比较粗糙,只实现了算法,细节的部分还待完善,呵呵)。
首先在主窗体中声明表示个体的结构体:

typedef struct//针对遗传算法定义的一个个体
{
int gene[1000];
double fitness;
double rfitness;
double cfitness;
}GenoType;
1
2
3
4
5
6
7
以及作为原材料的矩形板材:

typedef struct //矩形板
{
int l;
int w;
int x;
int y; //矩形的右下角
int flag;
}RectAA;

typedef struct //矩形板
{
int l;
int w;
int x;
int y;//矩形的左上角
}RectBB;
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
考虑到算法实现的可视化,中间大部分区域用于显示排样的结果,以彩色矩形块的方式显示出来,实现比较简单,不是重点。
下面是遗传算法实现的核心,这里只给出代表核心操作的几个函数:

//基因换位
void CMyDlg::swap(int *a, int *b)
{
int temp;
temp=*a;
*a=*b;
*b=temp;
}

//随机数
int CMyDlg::IntGenerate()
{

int RANGE_MIN=0;
int RANGE_MAX=m_Snumber;
int randpop=(rand()%1000/1000.0)*RANGE_MAX;
return randpop;
}

//选择种群
void CMyDlg::SecletMember()
{
int *a=new int[m_Snumber];
int x1,x2,j=0,temp1;

for(int i=0; i<m_Snumber; i++)
{
a[j]=i;
j++;
}
for(int j=0;j<m_NumAll;j++)
{

for(int i=0;i<1000;i++) //100次交换足以产生各种结果了
{
x1=IntGenerate();
x2=IntGenerate();
if (x1!=x2)
{
temp1=a[x1];
a[x1]=a[x2];
a[x2]=temp1;
}
}
for(int i=0;i<m_Snumber;i++)
population[j].gene[i]=a[i];
}
if(m_flag2)
{
for(int i=0;i<m_Snumber;i++)
population[m_NumAll].gene[i]=i;
population[m_NumAll].fitness=Valuecount(population[m_NumAll]);
}
}

//适应性
void CMyDlg::evaluate()
{
int j=0;
for(int i=0;i<(m_NumAll*5000000/m_GenS);i++)//1000控制界面速度
{ if(0==i%(m_NumAll*50000/m_GenS))
{
population[j].fitness=Valuecount(population[j]);
j++;
}
}

}

//评价
double CMyDlg::Valuecount(GenoType node)
{
int rl=rect[0].x;
for (int i=0;i<m_Snumber;i++)
{
rectdraw[i]=recto[node.gene[i]];
}
OnDrawfirst();
OnDrawbest();
for (int i=1;i<m_Snumber;i++)
{
if(rect[i].x>=rl)
rl=rect[i].x;
}

return 1.000*rl/m_width;
}


//选种
void CMyDlg::KeepTheBest()
{
int mem,i;
curbest=0;
for(mem=1;mem<m_NumAll;mem++)
if(population[mem].fitness<population[curbest].fitness)
curbest=mem;
if(population[curbest].fitness<population[m_NumAll].fitness)
population[m_NumAll]=population[curbest];//获得当前世代里的最好基因序列,并保存在当前世代的最后一个染色体中
}

//传代
void CMyDlg::elitist()
{
int i;
double best,worst;
int best_mem=0,worst_mem=0;

best=population[0].fitness;
worst=population[0].fitness;

for(i=1;i<m_NumAll;i++)
{
if(population[i].fitness<=best)
{
best=population[i].fitness;
best_mem=i;
}
if(population[i].fitness>=worst)
{
worst=population[i].fitness;
worst_mem=i;
}
}

if(best<=population[m_NumAll].fitness) //后一个体不如前一个体,就不要动前一世代
{
for(i=0;i<m_Snumber;i++)
population[m_NumAll].gene[i]=population[best_mem].gene[i];
population[m_NumAll].fitness=best;
}
else //否则
{
for(i=0;i<m_Snumber;i++)
population[worst_mem].gene[i]=population[m_NumAll].gene[i];
population[worst_mem].fitness=population[m_NumAll].fitness;
}
}

void CMyDlg::SecletBetter()
{
int mem,i;
double sum=0;
double *x=new double[m_NumAll];
double p;
int p1,p2;

for(mem=0;mem<m_NumAll;mem++)
sum+=population[mem].fitness;

for(mem=0;mem<m_NumAll;mem++)
x[mem]=sum-population[mem].fitness;
sum=0;
for(mem=0;mem<m_NumAll;mem++)
sum+=x[mem];
for(mem=0;mem<m_NumAll;mem++) //以对总体的贡献来确定其在种群中的相对适应度
population[mem].rfitness=(double)x[mem]/sum;
population[0].cfitness=population[0].rfitness;

for(mem=1;mem<m_NumAll;mem++)
{
population[mem].cfitness=population[mem-1].cfitness+population[mem].rfitness;
}
for(i=0;i<m_NumAll;i++)
{
p=rand()%1000/1000.0;
if(population[0].cfitness>p) //适者生存
newpopulation[i]=population[0];
else
{
for(int j=0;j<m_NumAll;j++)//弱肉强食
if(p>=population[j].cfitness && p<population[j+1].cfitness)
newpopulation[i]=population[j+1];
}
}

for(i=0;i<m_NumAll;i++)
population[i]=newpopulation[i];
/* for(i=0;i<100;i++) //随机PK
{
p1=(rand()%1000/1000.0)*100;
p2=(rand()%1000/1000.0)*100;
if(p1!=p2)
{
if (population[p1].rfitness>population[p2].rfitness)
{
population[p2]=population[p1];
}
else
population[p1]=population[p2];
}
}
*/
delete [] x;
}

void CMyDlg::crossover()//交叉
{
int i,j;
int min,max,flag;
double x;

for(i=0;i<m_Snumber;i++)
{
x=rand()%1000/1000.0;
if(x<m_pxCross)
{
min=0;max=0;
while(min==0)
min=IntGenerate();
while(max==0)
max=IntGenerate();
if(max<min)
{
int temp;
temp=max;
max=min;
min=temp;
}
flag=max;
for(j=min;j<=(max+min)/2;j++)//从min到max倒序
{
swap(&population[i].gene[j],&population[i].gene[flag]);
flag=flag-1;
}
}
}
}


void CMyDlg::mutate()//变异
{
int i;
int x1,x2;
double x;
for(i=0;i<m_Snumber;i++)
{
x=rand()%1000/1000.0;
if(x<m_pMutation)
{
x1=0;x2=0;
while(x1==0)
x1=IntGenerate();
while(x2==0)
x2=IntGenerate();
swap(&population[i].gene[x1],&population[i].gene[x2]);
}
}
}

//优化函数
void CMyDlg::OnProcess()
{
UpdateData(TRUE);
m_flag1=TRUE;
generation=0;
srand(time( NULL ) ); //取系统时间为随机种子
SecletMember();
evaluate();
KeepTheBest();
SetTimer(1,10,NULL);

}

//数据初始化
void CMyDlg::InitData(CString filename)
{
CString str;
DataFile.Open(filename,CFile::modeRead);
int i=0;
DataFile.ReadString(str);
while(str!=_T(""))
{
str.TrimLeft(' ');
Data[i][0]=atoi(str.Left(str.Find(' ')));
str=str.Right(str.GetLength()-str.Find(' ')-1);
Data[i][1]=atoi(str);
DataFile.ReadString(str);
i++;
}
m_Snumber=i;
DataFile.Close();


for (i=0;i<m_Snumber;i++)
{
rect[i].l=Data[i][0];
rect[i].w=Data[i][1];
recto[i]=rect[i];
}

sum=0;
for (i=0;i<m_Snumber;i++)
{
sum+=rect[i].l*rect[i].w;//根据面积计算利用率
}
if (sum>m_height*m_width)
MessageBox("超出原始板料!请重新输入");

for(i=0;i<m_Snumber;i++)//长宽统一
{ int a,b;
a=rect[i].l;
b=rect[i].w;
rect[i].l=max(a,b);
rect[i].w=min(a,b);
}

/* int max0,max1,max2,max3;
for (i=9;i>0;i--)
{
for (int j=9;j>9-i;j--)
{
if (rect[j][0]>rect[j-1][0])//按面积预先排列
{
max0=rect[j][0];
rect[j][0]=rect[j-1][0];
rect[j-1][0]=max0;
max1=rect[j][1];
rect[j][1]=rect[j-1][1];
rect[j-1][1]=max1;
max2=rect[j][2];
rect[j][2]=rect[j-1][2];
rect[j-1][2]=max2;
max3=rect[j][3];
rect[j][3]=rect[j-1][3];
rect[j-1][3]=max3;
}

}
}
*/
empty[0].l=m_width;
empty[0].w=m_height;
empty[0].x=0;
empty[0].y=m_height;
}

//画图
void CMyDlg::OnDrawfirst()
{

// m_flag0=TRUE;
// Invalidate(TRUE);
UpdateData(TRUE);
for(int i=0;i<m_Snumber;i++)
{
rect[i]=rectdraw[i];
}
empty[0].l=m_width;
empty[0].w=m_height;
empty[0].x=0;
empty[0].y=m_height;
for(int i=1;i<m_Snumber+1;i++)
{
empty[i].l=2000;
empty[i].w=2000;
empty[i].x=2000;
empty[i].y=2000;
}

CClientDC dc(this);
if(m_height!=0 &&m_width!=0)
{
CRect r;
GetClientRect(r);
r.left=r.left+21;
r.right=r.right-130;
r.bottom=r.bottom-18;
r.top=r.bottom-m_height*r.Width()/m_width;
dc.Rectangle (&r);
}
else
MessageBox("长宽不能为0!");
m_flag0=TRUE;
}

//绘制竞争胜利的个体
void CMyDlg::OnDrawbest()
{
int num=0;
int flag1;//横竖
while (num!=m_Snumber)
{
for(int i=0;i<num+1;i++ )
{
flag1=CalcuRate(empty[i],rect[num]);
if(3==flag1);
if(1==flag1)
{
rect[num].x=empty[i].x+rect[num].w;
rect[num].y=empty[i].y-rect[num].l;
empty[num+1].l=empty[i].l-rect[num].w;
empty[num+1].w=empty[i].w;
empty[num+1].x=empty[i].x+rect[num].w;
empty[num+1].y=empty[i].y;
empty[i].l=rect[num].w;
empty[i].w=empty[i].w-rect[num].l;
empty[i].y=empty[i].y-rect[num].l;
OrderEmpty();
rect[num].flag=flag1;
break ;
}
if(0==flag1)
{
rect[num].x=empty[i].x+rect[num].l;
rect[num].y=empty[i].y-rect[num].w;
empty[num+1].l=empty[i].l-rect[num].l;
empty[num+1].w=empty[i].w;
empty[num+1].x=empty[i].x+rect[num].l;
empty[num+1].y=empty[i].y;
empty[i].l=rect[num].l;
empty[i].w=empty[i].w-rect[num].w;
empty[i].y=empty[i].y-rect[num].w;
OrderEmpty();
rect[num].flag=flag1;
break ;
}
}
num++;
}
DrawBest();

}

//绘图
void CMyDlg::DrawBest()
{
CClientDC dc(this);
for (int i=0;i<m_Snumber;i++)
{
if(rect[i].l!=0 && rect[i].w!=0)
{
COLORREF color;
color=RGB((int)1.00*i*250/m_Snumber+20,(int)1.00*i*255/2*m_Snumber+50,(int)1.00*i*255/3*m_Snumber+50);

CRect r;
if (rect[i].flag==0)
{
r.left=Transformx(rect[i].x-rect[i].l);
r.top=Transformy(rect[i].y+rect[i].w);
r.right=Transformx(rect[i].x);
r.bottom=Transformy(rect[i].y);
dc.Rectangle(r);
dc.FillSolidRect(r.left+1,r.top+1,r.Width()-2,r.Height()-2,color);
}
if (rect[i].flag==1)
{
r.left=Transformx(rect[i].x-rect[i].w);
r.top=Transformy(rect[i].y+rect[i].l);
r.right=Transformx(rect[i].x);
r.bottom=Transformy(rect[i].y);
dc.Rectangle(r);
dc.FillSolidRect(r.left+1,r.top+1,r.Width()-2,r.Height()-2,color);
}
}
}

}

//计算比率
int CMyDlg::CalcuRate(RectBB empty,RectAA rect)
{

if((empty.w>=rect.l && empty.l>=rect.w) && (empty.w>=rect.w && empty.l>=rect.l))
return 1;
if((empty.w>=rect.l && empty.l>=rect.w) && (empty.l<rect.l || empty.w<rect.w))
return 1;
if((empty.w>=rect.w && empty.l>=rect.l) && (empty.l<rect.w || empty.w<rect.l))
return 0;
if((empty.l<rect.l || empty.w<rect.w) && (empty.l<rect.w || empty.w<rect.l))
return 3;
}

//边界x处理计算
int CMyDlg::Transformx(int x)
{ int xx;
CRect r;
GetClientRect(r);
r.left=r.left+21;
r.right=r.right-130;
r.bottom=r.bottom-18;
r.top=r.bottom-m_height*r.Width()/m_width;
xx=int(r.left+x*r.Width()/m_width+0.5);
return xx;
}

//边界y处理计算
int CMyDlg::Transformy(int y)
{
int yy;
CRect r;
GetClientRect(r);
r.left=r.left+21;
r.right=r.right-130;
r.bottom=r.bottom-18;
r.top=r.bottom-m_height*r.Width()/m_width;
yy=int(r.bottom-y*r.Width()/m_width+0.5);
return yy;

}


//排序处理
void CMyDlg::OrderEmpty()
{ RectBB mid;
for (int i=m_Snumber;i>0;i--)
{
for (int j=m_Snumber;j>m_Snumber-i;j--)
{
if (abs(empty[j].x-0)<abs(empty[j-1].x-0))
{
mid=empty[j];
empty[j]=empty[j-1];
empty[j-1]=mid;
}
}
}

}

//利用率计算
void CMyDlg::OnTimer(UINT nIDEvent)
{

if(generation<m_GenS)
{
generation++;
SecletBetter();
crossover();
mutate();
evaluate();
elitist();
}
else
{
KillTimer(TRUE);
CString str,str1;
str.Format("板材利用率:%.2f%%",100*sum/(Valuecount(population[m_NumAll])*m_height*m_width));
MessageBox(str);
m_flag1=TRUE;
m_flag2=FALSE;
}
CDialog::OnTimer(nIDEvent);
}

//绘图
void CMyDlg::DrawTheLast(GenoType node)
{

int rl=rect[0].x;
for (int i=0;i<m_Snumber;i++)
{
rectdraw[i]=recto[node.gene[i]];
}
OnDrawfirst();
OnDrawbest();
}
————————————————
版权声明:本文为CSDN博主「CouchDB」的原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接及本声明。
原文链接:https://blog.csdn.net/u011000290/article/details/46838079

原文地址:https://www.cnblogs.com/mjgw/p/12562484.html