该程序主要是将对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();
}
浙公网安备 33010602011771号