The knapsack Problem

Posted on 2012-10-19 19:16  cughuhao  阅读(158)  评论(0)    收藏  举报

该程序主要是将对Knapsack Problem的处理设计成一个类(KP类)来解决。先在Win32 Console Application中对该类进行测试,然后用MFC进行界面设计。其中类的声明放在kp.h中,类的实现放在kp.cpp中。

源代码

(1)kp.h

#include <time.h>

#ifndef KP_H_H

#define KP_H_H

const int attriMax=100;//每个个体属性的最大个数,或者称作每个个体染色体的长度

const int indiMax=100;//每个种群中个体的最大个数

struct indiMessage

{

         int valSum;//价值的和(即适应值)

         int volSum;//体积的和

         int index;//表示这是种群中的第index个个体

};//一个个体的信息

struct bestIndi

{

         int attri[attriMax];//该个体的属性(染色体)

         //int val,vol;//该个体的价值(适应值)、该个体所表示解的体积和

         int k;//该染色体的编码对应的十进制值

};//一个最优个体

struct _item//物品的信息

{

         int value;//物品的价值

         int volume;//物品占用的体积

         double k;//评价该物体的的一个参数,这里简单地设为value/volume。按k值的升序对物品进行排序,然后依次进行随机初始化

                 //这样并不能保证马上找到最优解,但可以加快找到最优解的速度。

};

class KP

{

private:

         int colony[indiMax][attriMax];//表示一个种群,colony[i][j]表示种群中第i个个体的第j个属性的值

                              //0表示不选,1表示选

         int tColony[indiMax][attriMax];//一个临时的种群

         indiMessage indiMsg[indiMax];//个体的信息

         float p[indiMax];//轮盘赌选择中的累积概率

         int Gi;

         clock_t start,end;

         void InitiateColony();//初始化种群函数

         void Assess();//个体评价函数

         void SaveBest();//保存最优个体函数

         int RouletteSelect();//轮盘赌选择

         void Crossover();//交差

         void Aberrance();//变异

         void PrintColony();//在屏幕上输出该个体的情况

public:

         //该问题的具体参数

         int attriNum;//属性的个数,即种群的大小

         _item item[attriMax];//每个可选物品的信息

         int knapsackVol;//背包的体积

         //解决该问题时使用的方法的参数

         int indiNum;//种群中个体的个数

         int G;//繁衍的代数

         double k;//变异的概率

         //问题的解

         bestIndi best[indiMax];//最优个体的集合(最优解不只一个)

         int bestNum;//最优解(个体)的个数

         int valMax,volMin;//最优解的价值总和和体积总和

         //对该参数下的方法的评价

         double time;//繁衍所用的时间

         void KnapsackProblem();//处理背包问题

         void PrintResult();//在Win32 Console Application中输出问题的解

};

#endif

(2)kp.cpp

#include "kp.h"

#include <time.h>

#include <algorithm>

#include <iostream>

using namespace std;

int CmpItem(_item a,_item b)

{

         return a.k>b.k;

}

void KP::InitiateColony()

{

         int volSum,i,j,p;

         for(i=0;i<attriNum;i++)

         {

                   item[i].k=1.0*item[i].value/item[i].volume;

         }

         sort(item,item+attriNum,CmpItem);

         for(i=0;i<indiNum;i++)

         {

                   volSum=0;

                   for(j=0;j<attriNum;j++)

                   {

                            colony[i][j]=rand()%2;

                            volSum+=item[j].volume*colony[i][j];

                            if(volSum>knapsackVol) break;

                   }

                   for(p=j;p<attriNum;p++)

                   {

                            colony[i][p]=0;

                   }

         }

}

int Cmp(indiMessage a,indiMessage b)

{

         return a.valSum>b.valSum;

}

void KP::Assess()//个体评价函数

{

         int i,j;

         for(i=0;i<indiNum;i++){

                   indiMsg[i].index=i;

                   indiMsg[i].valSum=0;

                   indiMsg[i].volSum=0;

                   for(j=0;j<attriNum;j++)

                   {

                            indiMsg[i].valSum+=item[j].value*colony[i][j];

                            indiMsg[i].volSum+=item[j].volume*colony[i][j];

                   }

                   while(indiMsg[i].volSum>knapsackVol)

                   {

                            indiMsg[i].volSum=0;indiMsg[i].valSum=0;

                            for(j=0;j<attriNum;j++)

                            {

                                     colony[i][j]=rand()%2;

                                     indiMsg[i].volSum+=item[j].volume*colony[i][j];

                                     indiMsg[i].valSum+=item[j].value*colony[i][j];

                            }

                   }

         }

         sort(indiMsg,indiMsg+indiNum,Cmp);

}

void KP::SaveBest()//保存最优个体函数

{

         int i,flag,k,cn;

         k=0;cn=1;

         for(i=attriNum-1;i>=0;i--)

         {

                   k+=colony[ indiMsg[0].index ][i]*cn;cn*=2;

         }

         if(indiMsg[0].valSum>valMax|| indiMsg[0].valSum==valMax&&indiMsg[0].volSum<volMin )

         {

                   for(i=0;i<attriNum;i++)

                   {

                            best[0].attri[i]=colony[ indiMsg[0].index ][i];

                   }

                   valMax=indiMsg[0].valSum;

                   volMin=indiMsg[0].volSum;

                   best[0].k=k;

                   bestNum=1;

         }

         if(indiMsg[0].valSum==valMax&&indiMsg[0].volSum==volMin)

         {

                   flag=1;

                   for(i=0;i<bestNum;i++){

                            if(best[i].k==k){

                                     flag=0;break;

                            }

                   }

                   if(flag){

                            for(i=0;i<attriNum;i++){

                                     best[bestNum].attri[i]=colony[ indiMsg[0].index ][i];

                            }

                            best[bestNum].k=k;

                            bestNum++;

                   }

         }

}

int KP::RouletteSelect()//轮盘赌选择

{

         float i;

         int select;

         i=rand()%100*1.0/100;

         select=0;

         while(i>p[select])

         {

                   select++;

         }

         return select;

}

void KP::Crossover()//交差

{

         int male,female,i,j,k,t;

         int sum=0;

         for(i=0;i<indiNum;i++)

         {

                   sum+=indiMsg[i].valSum;

         }

         for(i=0;i<indiNum;i++)

         {

                   p[i]=1.0*indiMsg[i].valSum/sum;

         }

         for(i=1;i<indiNum;i++)

         {

                   p[i]+=p[i-1];

         }

         for(i=0;i<indiNum-1;i+=2)

         {

                   male=RouletteSelect();female=RouletteSelect();

                   for(j=0;j<attriNum;j++)

                   {

                            tColony[i][j]=colony[male][j];

                            tColony[i+1][j]=colony[female][j];

                   }

                   k=rand()%attriNum;

 

                   for(j=0;j<=k;j++)

 

                   {

 

                            t=tColony[i][j];

 

                            tColony[i][j]=tColony[i+1][j];

 

                            tColony[i+1][j]=t;

 

                   }

 

         }

 

         if(indiNum%2==1)

 

         {

 

                   for(i=0;i<attriNum;i++)

 

                   {

 

                            tColony[indiNum-1][i]=colony[indiNum-1][i];

 

                   }

 

         }

 

         for(i=0;i<indiNum;i++)

 

         {

 

                   for(j=0;j<attriNum;j++)

 

                   {

 

                            colony[i][j]=tColony[i][j];

 

                   }

 

         }

 

}

 

void KP::Aberrance()//变异

 

{

 

         int i,j;

 

         for(i=0;i<indiNum;i++)

 

         {

 

                   j=rand()%(int(1.0/k)*attriNum);

 

                   if(j<attriNum)

 

                   {

 

                            colony[i][j]=(colony[i][j]+1)%2;

 

                   }

 

         }

 

}

 

 

 

void KP::PrintColony()//在屏幕上输出该个体的情况,用于Wind32 Console Application中

 

{

 

         int i,j;

 

         printf("G:%d                      valSum volSum\n",Gi);

 

         for(i=0;i<indiNum;i++)

 

         {

 

                   for(j=0;j<attriNum;j++)

 

                   {

 

                            printf("%d ",colony[ indiMsg[i].index ][j]);

 

                   }

 

                   printf("  %d     %d\n",indiMsg[i].valSum,indiMsg[i].volSum);

 

         }

 

         printf("\n");

 

}

 

int BestCmp(bestIndi a,bestIndi b)

 

{

 

         return a.k<b.k;

 

}

 

void KP::KnapsackProblem()

 

{

 

         int i,cn;

 

         start=clock();

 

         InitiateColony();

 

         Assess();

 

         valMax=0;volMin=0;

 

         for(i=0;i<attriNum;i++)

 

         {

 

                   best[0].attri[i]=colony[indiMsg[0].index][i];

 

                   valMax+=item[i].value*best[0].attri[i];

 

                   volMin+=item[i].volume*best[0].attri[i];

 

         }

 

         best[0].k=0;cn=1;

 

         for(i=attriNum-1;i>=0;i--)

 

         {

 

                   best[0].k+=best[0].attri[i]*cn;cn*=2;

 

         }

 

         bestNum=1;

 

         //PrintColony();

 

         for(Gi=0;Gi<G;Gi++)//繁衍

 

         {

 

                   Crossover();

 

                   Aberrance();

 

                   Assess();

 

                   SaveBest();

 

         }

 

         end=clock();

 

         time=(double)(end-start)/CLOCKS_PER_SEC;//计算繁衍所用的时间

 

         sort(best,best+bestNum,BestCmp);//对最优解按k值进行排序

 

}

 

void KP::PrintResult()//当在Wind32 Console Application中运行时调用,可在屏幕上输出最终的结果

 

{

 

         int i,j;

 

         for(i=0;i<bestNum;i++)//输出最优解

 

         {

 

                   for(j=0;j<attriNum;j++)

 

                   {

 

                            printf("%d ",best[i].attri[j]);

 

                   }

 

                   printf("  %d     %d   %d\n",valMax,volMin,best[i].k);

 

         }

 

         printf("bestNum:%d\n",bestNum);//输出最优解的个数

 

         printf("time: %.3lf\n",time);//输出繁衍所用的时间

 

}

 

(3)Start按钮的响应函数

 

void CKPMFCDlg::OnStart()

 

{

 

         // TODO: Add your control notification handler code here

 

         int p,q,i,j,k,t;

 

         KP kp;

 

         CString strAttriNum,strValue,strVolume,strKPVol,strIndiNum,strG,strK,strBestNum,strTime,strBest,strValMax,strVolMin;

 

         m_attriNum.GetWindowText(strAttriNum);//读取attriNum的值

 

         kp.attriNum=(int)atof(strAttriNum.GetBuffer(0));

 

         strAttriNum.ReleaseBuffer();

 

        

 

         m_value.GetWindowText(strValue);//读取value的值

 

         strValue+="**";

 

         j=0;

 

         for(p=0;strValue[p]!='*';)

 

         {

 

                   q=p;

 

                   while(strValue[q]!=' '&&strValue[q]!='*') q++;

 

                   k=1;

 

                   t=0;

 

                   for(i=q-1;i>=p;i--)

 

                   {

 

                            t+=(strValue[i]-48)*k;

 

                            k*=10;

 

                   }

 

                   //kp.value[j++]=t;

 

                   kp.item[j++].value=t;

 

                   p=q+1;

 

         }

 

         strValue.ReleaseBuffer();

 

        

 

         m_volume.GetWindowText(strVolume);//读取volume的值

 

         strVolume+="**";

 

         j=0;

 

         for(p=0;strVolume[p]!='*';)

 

         {

 

                   q=p;

 

                   while(strVolume[q]!=' '&&strVolume[q]!='*') q++;

 

                   k=1;

 

                   t=0;

 

                   for(i=q-1;i>=p;i--)

 

                   {

 

                            t+=(strVolume[i]-48)*k;

 

                            k*=10;

 

                   }

 

                   //kp.volume[j++]=t;

 

                   kp.item[j++].volume=t;

 

                   p=q+1;

 

         }

 

         strVolume.ReleaseBuffer();

 

 

 

         m_kpVol.GetWindowText(strKPVol);//读取背包的体积

 

         kp.knapsackVol=(int)atof(strKPVol.GetBuffer(0));

 

         strKPVol.ReleaseBuffer();

 

 

 

         m_indiNum.GetWindowText(strIndiNum);//读取indiNum

 

         kp.indiNum=(int)atof(strIndiNum.GetBuffer(0));

 

         strIndiNum.ReleaseBuffer();

 

         m_g.GetWindowText(strG);//读取G

 

         kp.G=(int)atof(strG.GetBuffer(0));

 

         strG.ReleaseBuffer();

 

         m_k.GetWindowText(strK);//读取变异概率k

 

         kp.k=atof(strK.GetBuffer(0));

 

         strK.ReleaseBuffer();

 

 

 

         kp.KnapsackProblem();//执行背包程序

 

 

 

         strValMax.Format("%d",kp.valMax);

 

         m_valMax.SetWindowText(strValMax);//输出所能装入的最大价值

 

         strValMax.ReleaseBuffer();

 

         strVolMin.Format("%d",kp.volMin);

 

         m_volMin.SetWindowText(strVolMin);//输出价值最大的情况下的最小占用体积

 

         strVolMin.ReleaseBuffer();

 

         strBestNum.Format("%d",kp.bestNum);

 

         m_bestNum.SetWindowText(strBestNum);//输出最优解的个数

 

         strBestNum.ReleaseBuffer();

 

 

 

         strBest=kp.best[0].attri[0]==0?"0":"1";//构造解的字符串

 

         strBest+=" ";

 

         for(i=1;i<kp.attriNum-1;i++)

 

         {

 

                   strBest+=kp.best[0].attri[i]==0?"0":"1";

 

                   strBest+=" ";

 

         }

 

         strBest+=kp.best[0].attri[kp.attriNum-1]==0?"0":"1";

 

         strBest+="\r\n";

 

         for(i=1;i<kp.bestNum;i++)

 

         {

 

                   for(j=0;j<kp.attriNum-1;j++)

 

                   {

 

                            strBest+=kp.best[i].attri[j]==0?"0":"1";

 

                            strBest+=" ";

 

                   }

 

                   strBest+=kp.best[i].attri[kp.attriNum-1]==0?"0":"1";

 

                   strBest+="\r\n";

 

         }

 

         m_best.SetWindowText(strBest);//输出最优解字符串(可能有多个)

 

         strBest.ReleaseBuffer();

 

 

 

         strTime.Format("%.3f",kp.time);

 

         m_time.SetWindowText(strTime);//输出繁衍所用的时间

 

         strTime.ReleaseBuffer();

 

}

 

 

 

 

 

 

 

 

 

 

 

(4)About按钮的响应函数

 

void CKPMFCDlg::OnAbout()

 

{

 

         // TODO: Add your control notification handler code here

 

         CAboutDlg aboutDlg;

 

         aboutDlg.DoModal();

 

}

 

博客园  ©  2004-2026
浙公网安备 33010602011771号 浙ICP备2021040463号-3