zoukankan      html  css  js  c++  java
  • 关于矩形排样问题(三)

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

    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

  • 相关阅读:
    织梦dedecms上传漏洞uploadsafe.inc.php修复
    dedecms漏洞修复大全含任意文件上传漏洞与注入漏洞
    DEDECMS批量导入excel数据到后台文章系统的开发教程
    使用DEDE织梦计划任务功能定时更新首页
    如何解决织梦DedeCms文章标题字数长度限制的方法教程
    织梦后台点击网站主页跳转到../index.php?upcache=1删除方法
    dedecms漏洞修复大全含任意文件上传漏洞与注入漏洞
    dedecms模板中联动菜单高级使用技巧
    解决dede的loop中无法使用limit的方案+文章前数字序号
    DEDECMS 又一种隔行换色和分组加线的方法
  • 原文地址:https://www.cnblogs.com/mjgw/p/12562484.html
Copyright © 2011-2022 走看看