找回密碼
 立即注冊(cè)

QQ登錄

只需一步,快速開始

搜索
查看: 2444|回復(fù): 0
收起左側(cè)

蟻群算法求解01背包

[復(fù)制鏈接]
ID:107189 發(fā)表于 2016-3-5 22:59 | 顯示全部樓層 |閱讀模式

一、問題描述

一個(gè)旅行者有一個(gè)最多能用m公斤的背包,現(xiàn)在有n件物品,它們的重量分別是W1,W2,..., Wn,它們的價(jià)值分別為V1,V2,...,Vn.若每種物品只有一件求旅行者能獲得最大總價(jià)值。

 

二、蟻群算法描述

       蟻群算法是對(duì)自然界螞蟻的覓食尋路方式進(jìn)行模擬而得出的一種仿生算法。這種算法有別于傳統(tǒng)編程模式,其優(yōu)勢(shì)在于,避免了冗長的編程和籌劃,程序本身是基于一定規(guī)則的隨機(jī)運(yùn)行來尋找最佳配置。也就是說,當(dāng)程序最開始找到目標(biāo)的時(shí)候,路徑幾乎不可能是最優(yōu)的,甚至可能是包含了無數(shù)錯(cuò)誤的選擇而極度冗長的。但是,程序可以通過螞蟻尋找食物的時(shí)候的信息素原理,不斷地去修正原來的路線,使整個(gè)路線越來越短,也就是說,程序執(zhí)行的時(shí)間越長,所獲得的路徑就越可能接近最優(yōu)路徑。這看起來很類似與我們所見的由無數(shù)例子進(jìn)行歸納概括形成最佳路徑的過程。實(shí)際上好似是程序的一個(gè)自我學(xué)習(xí)的過程。

這種優(yōu)化過程的本質(zhì)在于:

選擇機(jī)制:信息素越多的路徑,被選擇的概率越大。

更新機(jī)制:路徑上面的信息素會(huì)隨螞蟻的經(jīng)過而增長,而且同時(shí)也隨時(shí)間的推移逐漸揮發(fā)消失。

協(xié)調(diào)機(jī)制:螞蟻間實(shí)際上是通過分泌物來互相通信、協(xié)同工作的。

蟻群算法正是充分利用了選擇、更新和協(xié)調(diào)的優(yōu)化機(jī)制,即通過個(gè)體之間的信息交流與相互協(xié)作最終找到最優(yōu)解,使它具有很強(qiáng)的發(fā)現(xiàn)較優(yōu)解的能力。

 

三、問題實(shí)現(xiàn)分析

1、針對(duì)于01背包問題,所要求的是一個(gè)物品的排列問題,但是在蟻群算法的實(shí)現(xiàn)過程中要求有一個(gè)相同的起點(diǎn),因此我們?cè)黾恿艘粋(gè)共同的虛擬起點(diǎn),設(shè)為第0個(gè)物品。

2、對(duì)物品的選擇是整個(gè)算法的重點(diǎn),這個(gè)主要體現(xiàn)在對(duì)物品的選擇概率上。我們?nèi)缦露xANT數(shù)據(jù)結(jié)構(gòu):

struct{

    int path[nMAX];

    int v,c;

    bool pathTag[nMAX+1];

    int num;

}

其中,pathTag標(biāo)記了蟻群所訪問過的物品,c表示當(dāng)前螞蟻已經(jīng)占有的物品的重量。如果某個(gè)物品已經(jīng)被訪問過了,或者是該物品的重量加上已經(jīng)占有的物品的重量超過了背包的總負(fù)重量,則將其的被選擇的概率設(shè)為0。由于在c語言的實(shí)現(xiàn)過程中,涉及到一個(gè)浮點(diǎn)數(shù)的誤差問題,所以進(jìn)行比較的過程中都是通過DML_MIN進(jìn)行比較的。

 

四、實(shí)驗(yàn)環(huán)境

       Windows sp3 + vs2005命令行編譯器。

 

五、使用方法

       直接雙擊運(yùn)行aco.exe;

 

六、實(shí)驗(yàn)結(jié)果

       實(shí)驗(yàn)數(shù)據(jù)文件的格式為:物品數(shù)量、背包容量、各物品重量、各物品價(jià)值

1、  對(duì)于測試集test1.txt,最優(yōu)值為295,程序的運(yùn)行記過如下:

 

2、  對(duì)于測試集test2.txt,論文中通過遺傳算法所得的最優(yōu)值為1870,程序的運(yùn)行記過如下:

 

3、  對(duì)于測試集test3.txt,最優(yōu)值為1024,程序的運(yùn)行記過如下:

 

七、實(shí)驗(yàn)總結(jié)

       為了防止算法過早的收斂,可以通過減慢信息素的揮發(fā)過程,并且增加螞蟻覓食的次數(shù)。在實(shí)驗(yàn)的過程中螞蟻的只數(shù)對(duì)于整個(gè)的算法的影響并不是很大。

------------------------------------------------------------------------------------------------------------------------------------

代碼

/**
*作者:fern
*郵箱:yqshen3000@126.com
*xmu-3#221-2
*
**/

#include<stdio.h>
#include<string.h>
#include<time.h>
#include<process.h>
#include<stdlib.h>
#include<float.h>


const int nMAX = 100;//物品的最大個(gè)數(shù)
const int t = 1000;//覓食的次數(shù)
const int m = 50;//螞蟻個(gè)數(shù)
const double del = 0.4;
const double minP = 0.0000001;

typedef struct{
 int path[nMAX];
 int v,c;
 bool pathTag[nMAX+1];
 int num;
}ANT;

ANT ant

­;
ANT bestAnt;
double p[nMAX+1][nMAX+1];
int n;//物品數(shù)量
int w[nMAX];//單個(gè)物品的重量
int v[nMAX];//對(duì)應(yīng)物品的價(jià)值
int c;//背包的容量


void initACO(){
 double temp = 1.0 / (n*n);
 int i = 0;
 for(; i <= n; i++)
  for(int j=1; j<=n; j++)
   if(i == j)p[i][j]=0.0;
   else p[i][j] = temp;
 for(i=0; i<=n; i++)
  p[i][0]=0.0;
 bestAnt.v = 0;
}
 
bool selectThing(ANT &singleant, int beg){
 double total = 0.0;
 double select[nMAX+1];
 int i=1;
 for(; i < n+1; i++)
  if(!singleant.pathTag[i]&&(c-singleant.c-w[i-1]>=0)){
   total += p[beg][i];
   select[i] = p[beg][i];
  }
  else
   select[i] = 0.0;
 if(total<DBL_MIN)return false;//已經(jīng)沒有可以選擇的物品
 
 select[0]=0.0;
 for(i = 1; i< n+1;i++)
  select[i] = select[i-1] +  select[i]/total;
 select[--i] += DBL_MIN;
 double randP = rand()%1000*1.0/1000;
 if(randP<DBL_MIN)randP=DBL_MIN;
 for(i=1;select[i]<randP&&i<n+1;i++);
 singleant.path[singleant.num] = i;
 singleant.v += v[--i];
 singleant.c += w[i];
 singleant.pathTag[++i] = true;
 singleant.num ++;
 return true;
 }

int changeP(){
 int index = 0, i;
 for(i=1;i < m; i++)
  if(ant[i].v>ant[index].v)index = i;

 for(i = 0;i < n+1; i++)
  for(int j=1; j<n+1; j++)
   p[i][j] *= 1-del;
 if(ant[index].num == 0){
  printf("輸入的數(shù)據(jù)有誤\n");
  exit(0);
  }
 double add = del/ant[index].num;
 int beg = 0;
 for(i=0; i < ant[index].num; i++){
  p[beg][ant[index].path[i]] += add;
  beg = ant[index].path[i];
 }

 return index; 
}
 
void aco(){
 initACO();
 srand(time(NULL));
 
 int i;
 for(i=0; i< t; i++){
  int j = 0;
  for(;j < m; j++){
   //初始化螞蟻
   memset(ant[j].path,0,n*sizeof(int));
   ant[j].v = 0;
   ant[j].c = 0;
   memset(ant[j].pathTag,false,(n+1)*sizeof(bool));
   ant[j].num = 0;
   int beg = 0;
   while(true){
    bool tag = selectThing(ant[j],beg);
    if(!tag)break;
    beg = ant[j].path[ant[j].num-1];
   }
  }
  
  //更新信息素
  int index = changeP();
  /*printf("\n\n第%d次,最好的選擇為:\n",i+1);
  for(j=0; j<ant[index].num; j++)
   printf("%d\t",ant[index].path[j]);
  printf("\n物體總價(jià)值為%d\n",ant[index].v);*/
  
  if(bestAnt.v < ant[index].v){
   bestAnt.c = ant[index].c;
   bestAnt.num = ant[index].num;
   bestAnt.v = ant[index].v;
   memcpy(bestAnt.path,ant[index].path,ant[index].num*sizeof(int));
   memcpy(bestAnt.pathTag,ant[index].pathTag,ant[index].num*sizeof(bool));
  }

 }
}

void init(){
 char fileName[512];
 printf("請(qǐng)輸入文件名\n");
 scanf("%s",fileName);
 //char *fileName = "test2.txt";
 printf("測試的文件為:%s\n",fileName);
 FILE *fp = fopen(fileName,"r");
 fscanf(fp,"%d",&n);
 if(n>nMAX){
  printf("物品數(shù)量過多\n");
  system("pause");
  exit(0);
  }
 printf("物體數(shù)量為:%d\n",n);
 fscanf(fp,"%d",&c);
 printf("背包總?cè)萘繛椋?d\n",c);
 printf("物品重量分別為:\n");
 int i = 0;
 for(; i < n; i++){
  fscanf(fp,"%d",&w[i]);
  printf("%4d",w[i]);
 }
 printf("\n物品價(jià)值分別為:\n");
 for(i = 0; i < n; i++){
  fscanf(fp,"%d",&v[i]);
  printf("%4d",v[i]);
 }
}

int main(){
 init();
 aco();
 printf("\n最好的選擇是:\n");
 for(int j=0; j<bestAnt.num; j++)
  printf("%2d、第%2d個(gè)物品:<%3d,%3d>\n",j+1,bestAnt.path[j],w[bestAnt.path[j]-1],v[bestAnt.path[j]-1]);
 printf("物體總價(jià)值為%d\n",bestAnt.v);
 printf("物體總重量為%d\n",bestAnt.c);
 system("pause");
 return 0;
 }

回復(fù)

使用道具 舉報(bào)

本版積分規(guī)則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術(shù)交流QQ群281945664

Powered by 單片機(jī)教程網(wǎng)

快速回復(fù) 返回頂部 返回列表