原创:TSP问题解决方案-----禁忌搜索算法C实现
本文着重于算法的实现,对于理论部分可自行查看有关资料可以简略参考该博文:http://blog.csdn.net/u013007900/article/details/50379135
本文代码部分基于C实现,源码如下:
/***************************************************************************** ** Copyright: NEW NEU laboratory ** File name: CTSP ** Description:禁忌搜索算法解决TSP问题 ** Author: 1702-GCJ ** Version: 1.1 ** Date: 2017/10/3 ** History: 无 ** Modification: IsFindTabu(Queue * Q,const Tabu *item) *****************************************************************************/ #include"stdio.h" #include"stdlib.h" #include"string.h" #include "time.h" #define CityNum 31 //城市的数量 #define TabuLength 21 //禁忌表长度(根号下的 种类) #define Neighbor 400 //邻居个数 #define MaxNG 400 //迭代次数 ; //当前迭代次数 ; //渴望水平 (即最短距离) typedef int ElementType; ElementType **Distance; //存储各个城市之间的距离矩阵的指针 数据都是取整的 /***************************************************************************************读取数据区******************************************/ /************************************************* **Function: MemBlockCity **Description: 申请存储城市距离空间 **Calls: 无 **Called By: ReadDataTxt() **Input: 无 **Output: 无 **Return: 指向存储城市距离空间的指针 **Others: 用完需要释放掉相应内存 *************************************************/ ElementType ** MemBlockCity(); /************************************************* **Function: PrintCityDistance **Description: 显示Distance信息 **Calls: 无 **Called By: main() **Input: Distance 全局变量的指针 **Output: 无 **Return: void **Others: 无 *************************************************/ void PrintCityDistance( ElementType ** distance); /************************************************* **Function: ReadDataTxt **Description: 从txt文档中读取数据 **Calls: MemBlockCity() **Called By: main **Input: 无 **Output: 无 **Return: void **Others: 里面直接用的全局变量 指针Distance *************************************************/ void ReadDataTxt(); /************************************************* **Function: WriteDataTxt **Description: 将Distance全局数组数据写到txt文档中去 **Calls: 无 **Called By: main() **Input: 无 **Output: 无 **Return: void **Others: 里面用到了宏值CityNum值 *************************************************/ void WriteDataTxt(); /**********************************************************************************禁忌表操作区*******************************************/ typedef struct _Tabu{ int smallNum; int bigNum; //存储数量大的元素 }Tabu; //禁忌表结构 typedef struct _Queue{ Tabu *tabuList;//队列空间指针 int rear; //指向尾部 int front; //指向队列的头部 int maxSize; //记录队列的最大个数 int count; //记录资源个数 判断队列空满 int tabuIndex; //在禁忌表中找到禁忌元素时 存储该值在禁忌表中的位置 }Queue;//循环队列的形式 /************************************************* **Function: CreateQueue **Description: malloc一个禁忌表队列并初始化 **Calls: 无 **Called By: main() **Input: tabuLength 禁忌表数据长度 **Output: 无 **Return: Queue * 队列变量 **Others: 里面用到了宏值CityNum值 ,用完需要释放掉相应内存 *************************************************/ Queue * CreateQueue(int tabuLength); /************************************************* **Function: UpdateTabu **Description: 更新禁忌表 **Calls: IsFindTabu() **Called By: TSP() **Input: Q 禁忌表队列 item 加入禁忌表的Tabu结构的变量 **Output: 无 **Return: void **Others: *************************************************/ void UpdateTabu(Queue *Q,Tabu *item); /************************************************* **Function: IsFindTabu **Description: 禁忌表中是否找到这个元素 **Calls: 无 **Called By: UpdateTabu() TSP() **Input: Q 禁忌表队列 item 判断其是否在禁忌表中的Tabu结构的变量的指针 **Output: 无 **Return: 0 没有找到这个元素 1 找到这个元素了 **Others: *************************************************/ static int IsFindTabu(Queue * Q,const Tabu *item); /****************************************************************************2Opt邻域+TSp核心算法*********************************************/ //定义解的存储类型 向量形式 typedef struct _Solve{ ElementType *initSolution; //初始解 ElementType *currentSolution; //当前解 ElementType * optimalSolution; //最优解 ElementType *tempSolution; //临时解 ElementType lastdistance; //上次记录的总距离 ElementType initdistance; //定义初始距离 }StrSolve; typedef struct _MotionTable{ Tabu tabu; //存储改变的元素 ElementType changedistance; //改变的距离 }MotionTable;//记录2opt邻域移动信息 StrSolve * SolutionSpace ; //解空间(包含当前解和初始解)指针 MotionTable *motionTable; //移动元素信息 (一个表格) /************************************************* **Function: CreateMotionStruct **Description: 创建并初始化2-Opt 移动信息表格 **Calls: 无 **Called By: Init2Opt() **Input: neighbor 邻居数量 **Output: 无 **Return: MotionTable *指针变量 **Others: 不用这块内存的时候要释放掉 ! *************************************************/ MotionTable* CreateMotionStruct(int neighbor); /************************************************* **Function: CreateSolutionSpace **Description: 创建并初始化解空间 **Calls: 无 **Called By: Init2Opt() **Input: cityNum 城市数量 **Output: 无 **Return: StrSolve *指针变量 **Others: 不用这块内存的时候要逐一释放掉 ! *************************************************/ StrSolve *CreateSolutionSpace(int cityNum); /************************************************* **Function: GetInitSolution **Description: 获得初始解 **Calls: 无 **Called By: Init2Opt() **Input: StrSolve * 指针变量 **Output: 无 **Return: StrSolve *指针变量 **Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! *************************************************/ void GetInitSolution(StrSolve * strSolve); /************************************************* **Function: Init2Opt **Description: 初始化TSP需要用的值 **Calls: CreateMotionStruct() CreateSolutionSpace() GetInitSolution() **Called By: main **Input: 无 **Output: 无 **Return: void **Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! 不知道为什么只能在Main函数中调用否则 会出现段错误 *************************************************/ void Init2Opt(); /************************************************* **Function: FindPosition **Description: 在数组中找到指定元素值的位置 **Calls: **Called By: Get2OptChangeDistance() TSP() **Input: solution 一维数组指针 tabu Tabu结构指针 **Output: 无 **Return: void **Others: 这里是从solution[1]开始查找到的! *************************************************/ static void FindPosition(const ElementType * solution,Tabu *tabu); /************************************************* **Function: FindPosition **Description: 获得2邻域变化值 **Calls: FindPosition() **Called By: Get2optSolution() **Input: tabu Tabu结构指针 solution 一维数组指针 **Output: 无 **Return: ElementType 2邻域城市变化值 **Others: 返回的值越小越好 ! *************************************************/ static ElementType Get2OptChangeDistance(Tabu * tabu,const ElementType * solution); /************************************************* **Function: Get2optSolution **Description: 得到1个2邻域解 将移动元素,及其导致路径的变化值 存储到移动表中 **Calls: Get2OptChangeDistance() **Called By: TSP() **Input: strSolve 解空间指针 motiontable 移动表指针 **Output: 无 **Return: void **Others: 随机数要注意! *************************************************/ void Get2optSolution(const StrSolve * strSolve,MotionTable *motiontable ); /************************************************* **Function: Insert_Sort **Description: 按从小到大排序 插入排序 将制定的类数组变量 的内容进行排序 **Calls: 无 **Called By: FindBestMotionValue() **Input: motiontable 移动表指针 n为类数组 元素个数 **Output: 无 **Return: void **Others: *************************************************/ void Insert_Sort (MotionTable * motiontable,int n); /************************************************* **Function: FindBestMotionValue **Description: 找到移动表中最小的值 即为最优值 **Calls: Insert_Sort() **Called By: TSP() **Input: motiontable 移动表指针 **Output: 无 **Return: MotionTable *型的指针 存储移动表中最好值的表格指针 **Others: *************************************************/ MotionTable * FindBestMotionValue( MotionTable * motiontable); /************************************************* **Function: GetInitLevel **Description: 获取初始解的渴望水平 **Calls: **Called By: TSP() **Input: distance 存储城市的矩阵指针 initSolution 初始解指针 **Output: 无 **Return: 初始解的渴望水平 **Others: *************************************************/ int GetInitLevel( ElementType **distance,ElementType * initSolution); /************************************************* **Function: TSP **Description: TSP核心算法 **Calls: GetInitLevel() **Called By: TSP() Get2optSolution() FindBestMotionValue() UpdateTabu() FindPosition() memcpy() **Input: distance 存储城市的矩阵指针 solutionSpace 解空间指针 motiontable 移动表 desireLevel 渴望水平 queue 禁忌表队列指针 **Output: 最优解信息 **Return: void **Others: *************************************************/ void TSP( ElementType **distance, StrSolve * solutionSpace ,MotionTable *motiontable,int *desireLevel,Queue *queue); /************************************************* **Function: MemFree **Description: 释放申请的动态内存 **Calls: free() **Called By: main() **Input: distance 存储城市距离的变量指针 queue 禁忌表队列 motiontable 移动表的指针 strSolve 解空间的指针 **Output: 无 **Return: void **Others: 这里也可以一步一步的释放掉 各自的指针 因为就用一个.c所以释放内存的操作都在这里进行 *************************************************/ void MemFree(ElementType ** distance,Queue *queue,MotionTable *motiontable,StrSolve *strSolve); /*******************************************************************************MAIN函数*************************************/ int main(int argc,char *argv[]) { // Tabu item; clock_t start, finish; double duration; Queue * queue = CreateQueue(TabuLength); //创建一个禁忌表队列 本身就初始化好了 Init2Opt();//初始化相关 // 设置随机数种子 为以后使用rand()做准备 srand((unsigned )); start = clock(); ReadDataTxt(Distance);//必须放在前面 读取数据后 才能操作 // PrintCityDistance(Distance); //显示二维数组的数据 只显示5X5 // WriteDataTxt(Distance);//将distance 数据写入txt TSP( Distance,SolutionSpace ,motionTable,&DesireLevel,queue); //// //将得到的最优解 从新用TSP算法算 // memcpy( SolutionSpace->initSolution,SolutionSpace->optimalSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间 // printf("\n新初始解的渴望水平:%d \n",GetInitLevel(Distance,SolutionSpace->optimalSolution)); // TSP( Distance,SolutionSpace ,motionTable,&DesireLevel,queue); // finish = clock(); duration = (double)(finish - start) / CLOCKS_PER_SEC; printf("\n TSP算法运行时间:%.4f秒 \n",duration); MemFree(Distance, queue,motionTable,SolutionSpace); ; } /************************************************************************读取数据区***********************************************/ /************************************************* **Function: MemBlockCity **Description: 申请存储城市距离空间 **Calls: 无 **Called By: ReadDataTxt() 在txt文档中读取数据 **Input: 无 **Output: 无 **Return: 指向存储城市距离空间的指针 **Others: 无 *************************************************/ ElementType ** MemBlockCity() { ElementType ** Distance; ; //动态申请一块内存存储城市之间的数据 Distance = (ElementType **)malloc(sizeof(ElementType *)*CityNum); ;i< CityNum ; i++){ Distance[i] = (ElementType *)malloc(sizeof (ElementType )* CityNum); } return Distance; } /************************************************* **Function: PrintCityDistance **Description: 显示Distance信息 这里仅仅显示了CityNum-25个元素 因为屏幕显示不开 **Calls: 无 **Called By: main() **Input: Distance 全局变量的指针 **Output: 无 **Return: void **Others: 无 *************************************************/ void PrintCityDistance( ElementType ** distance) { int i,j; ; i< CityNum-;i++){ ;j<CityNum-;j++) printf("%d ",distance[i][j]); printf("\n"); } } /************************************************* **Function: ReadDataTxt **Description: 从txt文档中读取数据 **Calls: MemBlockCity() **Called By: main() **Input: 无 **Output: 无 **Return: void **Others: 里面直接用的全局变量 指针Distance *************************************************/ void ReadDataTxt() { // FILE *fpRead=fopen("F:\\GCJ\\Desktop\\智能优化方法作业\\data.txt","r"); FILE *fpRead=fopen("data.txt","r"); //从data.txt中读取数据 int i,j; if(fpRead==NULL){ printf("open file data.txt failed!\n"); exit(); } Distance = MemBlockCity(); //申请一块存储城市数量空间 ;i<CityNum;i++){ Distance[i][i] = ; ;j < CityNum;j++ ){ fscanf(fpRead,"%d",&Distance[i][j]);//自动读取数据 只要自己能够控制好存储位置即可 Distance[j][i] = Distance[i][j]; } } fclose(fpRead); } /************************************************* **Function: WriteDataTxt **Description: 将Distance全局数组数据写到txt文档中去 **Calls: 无 **Called By: main() **Input: 无 **Output: 无 **Return: void **Others: 里面用到了宏值CityNum值 *************************************************/ void WriteDataTxt(ElementType **distance) { FILE *fpWrite; int i,j; fpWrite=fopen("F:\\GCJ\\Desktop\\智能优化方法作业\\data.txt","w"); //从data.txt中写数据 ;i< CityNum;i++){ ;j<CityNum;j++) fprintf(fpWrite,"%d ",distance[i][j]);//这里%d后面必须要有空格 否则 直接输出连续的数字 fprintf(fpWrite,"\n"); } fclose(fpWrite); } /**************************************************************禁忌表操作区*****************************************************/ /************************************************* **Function: CreateQueue **Description: malloc一个禁忌表队列并初始化 **Calls: 无 **Called By: main() **Input: tabuLength 禁忌表数据长度 **Output: 无 **Return: Queue * 队列变量 **Others: 里面用到了宏值CityNum值 *************************************************/ Queue * CreateQueue(int tabuLength) { Queue * queue = (Queue *)malloc(sizeof(struct _Queue));//申请一块队列变量 //queue->tabuList =(ElementType *)malloc(sizeof(ElementType)*MaxSize);//申请一块数组空间 queue->tabuList =(Tabu *)malloc(sizeof(Tabu)*tabuLength);//21的长度 queue->front = ; queue->rear = ;//头尾 都为0 queue->maxSize = tabuLength; queue->count =; queue->tabuList[].smallNum = ; queue->tabuList[].bigNum = ; return queue; } /************************************************* **Function: IsFindTabu **Description: 禁忌表中是否找到这个元素 **Calls: 无 **Called By: UpdateTabu() TSP() **Input: Q 禁忌表队列 item 判断其是否在禁忌表中的Tabu结构的变量的指针 **Output: 无 **Return: 0 没有找到这个元素 1 找到这个元素了 **Others: *************************************************/ static int IsFindTabu(Queue * Q,const Tabu *item) { Tabu tabu; int i; ; //将要禁忌的值按顺序放在中间变量中 方便加入到禁忌表中 if( (*item).bigNum >= (*item).smallNum ){ tabu.bigNum = (*item).bigNum; tabu.smallNum = (*item).smallNum; } else{ tabu.bigNum = (*item).smallNum; tabu.smallNum = (*item).bigNum; } //查找禁忌表中是否有这个禁忌元素 没有的话 插入元素在头部 否则把这个元素加上惩罚政策加入到禁忌表的头部 其他依次降序 for(i = Q->front; (i%TabuLength)!= Q->rear; ){//这个查找函数有问题了 因为循环队列的话 队列慢点话 rear = front 如何解决? if( (tabu.smallNum == Q->tabuList[i].smallNum ) && ( tabu.bigNum == Q->tabuList[i].bigNum ) ){ //说明在禁忌表中找到这个元素了 那么就惩罚这个 放在最前面 //把第一个元素放入 这个值 剩下的依次 递减排列 // printf("在禁忌表中找到了%d %d\n",tabu.bigNum,tabu.smallNum); //新加 记录位置 Q->tabuIndex = i; IsFindFlag = ; return IsFindFlag ; //表示不管了 } if(++i >= TabuLength)//仅仅让i 在 0 - Tabulength范围内遍历 i = ; } if( Q->count >= TabuLength ){//说明禁忌表满 那么rear值就需要访问了 否则不需要访问 if( i%TabuLength == Q->rear )//因为循环队列寻找的时候 最后一个元素 无法通过for循环遍历到 if( (tabu.smallNum == Q->tabuList[i].smallNum ) && ( tabu.bigNum == Q->tabuList[i].bigNum ) ){ // printf("找到了最新的了%d %d\n",tabu.smallNum,tabu.bigNum); //新加 记录位置 Q->tabuIndex = Q->rear; IsFindFlag = ; return IsFindFlag ; //表示不管了 } } return IsFindFlag;//之前这里就忘了加了 注意这点 !! } /************************************************* **Function: UpdateTabu **Description: 更新禁忌表 **Calls: IsFindTabu() **Called By: TSP() **Input: Q 禁忌表队列 item 加入禁忌表的Tabu结构的变量的指针 **Output: 无 **Return: void **Others: *************************************************/ void UpdateTabu(Queue *Q,Tabu *item) { Tabu tabu; Tabu temptabu; int i; //将要禁忌的值按顺序放在中间变量中 方便加入到禁忌表中 if( (*item).bigNum >= (*item).smallNum ){ tabu.bigNum = (*item).bigNum; tabu.smallNum = (*item).smallNum; } else{ tabu.bigNum = (*item).smallNum; tabu.smallNum = (*item).bigNum; } if( !IsFindTabu(Q,item) ){ //如果没有找到 那么直接在队列插入这个元素 if( Q->count < TabuLength ){ //说明队列不满 那就直接插入元素 Q->count++ ;//最后满的时候为21个元素 Q->tabuList[Q->rear++] = tabu;//在后面插入 然后从前面取出元素 if( Q->rear >= TabuLength)//到了尾部的话 就直接从前面开始存储 尾部先存储后+1 --Q->rear ;//说明禁忌表满了的时候 让rear指向最后一个元素即可 } else{//满了的话 就直接头部删除 尾部加入 //不是真正的删除 仅仅是释放掉这块存储空间 if( ++Q->front >= TabuLength ) Q->front =; if( ++Q->rear >= TabuLength)//到了尾部的话 就直接从前面开始存储 尾部先存储后+1 Q->rear = ; Q->tabuList[Q->rear] = tabu; } } else{//在禁忌表中找到这个元素的时候 需要进行惩罚 将这个值放在头部,而该值前面的数依次向后排 int j,k; j = Q->tabuIndex ; //禁忌表中找到的该值的索引 k = Q->front; //禁忌表头部索引 if( Q->tabuIndex >= Q->front ){ //说明禁忌表没有满 或者 禁忌表满了 但是移动仅仅在Q->front 到这个索引即可 for( --j ;j >= k ; --j){ Q->tabuList[j+] = Q->tabuList[j]; }/*for end*/ } else{ //禁忌表满了且 Q->front 值大于 Q->tabuIndex for( ;j == Q->front; --j ){ ) Q->tabuList[j] =Q->tabuList[j-]; else{ //j == 0 j = TabuLength ; Q->tabuList[] = Q->tabuList[j-]; } }/*for ...end */ } //惩罚策略 Q->tabuList[Q->front] = tabu; }/*if find .. else ..end*/ } /******************************************************************************************2Opt邻域+TSp核心算法***********************************/ /************************************************* **Function: CreateMotionStruct **Description: 创建并初始化2-Opt 移动信息表格 **Calls: 无 **Called By: Init2Opt() **Input: neighbor 邻居数量 **Output: 无 **Return: MotionTable *指针变量 **Others: 不用这块内存的时候要释放掉 ! *************************************************/ MotionTable* CreateMotionStruct(int neighbor) { int i; MotionTable * motiontable = (MotionTable *)malloc(sizeof(MotionTable)*neighbor ); ;i< neighbor;i++){ motiontable->tabu.smallNum =; motiontable->tabu.bigNum = ; motiontable->changedistance = ; } return motiontable; } /************************************************* **Function: CreateSolutionSpace **Description: 创建并初始化解空间 **Calls: 无 **Called By: Init2Opt() **Input: cityNum 城市数量 **Output: 无 **Return: StrSolve *指针变量 **Others: 不用这块内存的时候要逐一释放掉 ! *************************************************/ StrSolve *CreateSolutionSpace(int cityNum) { int i; StrSolve *strSolve = (StrSolve *)malloc( sizeof(StrSolve) ) ; strSolve->initSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum ); strSolve->currentSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum ); strSolve->optimalSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum ); strSolve->tempSolution = ( ElementType *)malloc(sizeof(ElementType)*cityNum ); //初始化解空间 ;i< cityNum;i++){ strSolve->initSolution[i] = (ElementType); strSolve->currentSolution[i] = (ElementType); strSolve->optimalSolution[i] = (ElementType); strSolve->tempSolution[i] = (ElementType); } strSolve->lastdistance = ;//记录上次迭代获得最好的距离值 return strSolve; } /************************************************* **Function: GetInitSolution **Description: 获得初始解 **Calls: 无 **Called By: Init2Opt() **Input: StrSolve * 指针变量 **Output: 无 **Return: StrSolve *指针变量 **Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! @brief :思路 可以用一个记录初始解的类数组(申请的内存 大小为初始解的元素个数),之后循环 CityNum-1次,不断的产生1-CityNum-1的随机数 没产生一个就记录这个值 之后再次产生与上次不同的随机数 ,依次这样循环即可 不过速度上会很慢 *************************************************/ void GetInitSolution(StrSolve * strSolve) { int i; //默认从0号城市顺序开始 这里的0是固定不动的 ;i<CityNum;i++){ strSolve->initSolution[i] = i; strSolve->currentSolution[i] = i; strSolve->optimalSolution[i] = i; strSolve->tempSolution[i] = i; } } /************************************************* **Function: Init2Opt **Description: 初始化TSP需要用的值 **Calls: CreateMotionStruct() CreateSolutionSpace() GetInitSolution() **Called By: main() **Input: 无 **Output: 无 **Return: void **Others: 这里在初始化解的时候可以用其他元启发式算法得出一个较好的解 ! 不知道为什么只能在Main函数中调用否则 会出现段错误 *************************************************/ void Init2Opt() { motionTable = CreateMotionStruct(Neighbor);//初始化变化表 记录变化邻居值 SolutionSpace = CreateSolutionSpace(CityNum);//创建解空间 GetInitSolution(SolutionSpace);//初始化解 } /************************************************* **Function: MemFree **Description: 释放申请的动态内存 **Calls: **Called By: main() **Input: distance 存储城市距离的变量指针 queue 禁忌表队列 motiontable 移动表的指针 strSolve 解空间的指针 **Output: 无 **Return: void **Others: 这里也可以一步一步的释放掉 各自的指针 因为就用一个.c所以释放内存的操作都在这里进行 *************************************************/ void MemFree(ElementType ** distance,Queue *queue,MotionTable *motiontable,StrSolve *strSolve) { ; ; //释放矩阵元素存储区 ;i < CityNum; i++){ free( distance[i] ); } free(distance); //释放移动表 free(motiontable); //释放掉队列区 free(queue->tabuList); free(queue); //释放解空间 free(strSolve->initSolution); free(strSolve->currentSolution); free(strSolve->optimalSolution); free(strSolve->tempSolution); free(strSolve); } /************************************************* **Function: FindPosition **Description: 在数组中找到指定元素值的位置 **Calls: **Called By: Get2OptChangeDistance() TSP() **Input: solution 一维数组指针 tabu Tabu结构指针 **Output: 无 **Return: void **Others: 这里是从solution[1]开始查找到的! *************************************************/ static void FindPosition(const ElementType * solution,Tabu *tabu) { int i; Tabu tempTabu; ; i< CityNum;i++){ if( solution[i] == tabu->smallNum ) tempTabu.smallNum = i; if( solution[i] == tabu->bigNum ) tempTabu.bigNum = i; } *tabu = tempTabu;//不能直接返回&tempTabu 因为这个是一个局部的变量 会有悬挂指针的后果 } /************************************************* **Function: FindPosition **Description: 获得2邻域变化值 **Calls: FindPosition() **Called By: Get2optSolution() **Input: tabu Tabu结构指针 solution 一维数组指针 **Output: 无 **Return: ElementType 2邻域城市变化值 **Others: 返回的值越小越好 ! *************************************************/ static ElementType Get2OptChangeDistance(Tabu * tabu,const ElementType * solution) { ElementType change1,change2; Tabu tempTabu1 = *tabu; Tabu tempTabu; change1 = change2 = ; FindPosition(solution,&tempTabu1); //此时这里的tempTabu1存储的就是指定元素在 解空间中的位置 tempTabu.bigNum = ( tempTabu1.bigNum >tempTabu1.smallNum )? tempTabu1.bigNum: tempTabu1.smallNum; tempTabu.smallNum = ( tempTabu1.bigNum >tempTabu1.smallNum )? tempTabu1.smallNum: tempTabu1.bigNum; ){//两个元素在解空间中的 位置相差1 ){ //最大值位置 在最后一个位置 change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ]+\ Distance[ solution[tempTabu.bigNum] ][ solution[ ] ]; change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\ Distance[ solution[tempTabu.smallNum] ][ solution[] ]; return (change2 - change1);//这个值越小越好 } else{ change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\ Distance[ solution[tempTabu.bigNum] ][ solution[ tempTabu.bigNum +] ]; change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\ Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.bigNum +] ]; return (change2 - change1); } } else{//两个元素位置 不挨着 ){ //最大值位置 在最后一个位置 change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\ Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.smallNum +] ] +\ Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.bigNum ] ] +\ Distance[ solution[tempTabu.bigNum] ][ solution[ ] ]; change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\ Distance[ solution[tempTabu.bigNum] ][ solution[tempTabu.smallNum+] ] +\ Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.smallNum ] ]+\ Distance[ solution[tempTabu.smallNum] ][ solution[] ]; return (change2 - change1);//这个值越小越好 } else{ change1 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.smallNum] ] +\ Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.smallNum +] ] +\ Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.bigNum ] ] +\ Distance[ solution[tempTabu.bigNum] ][ solution[ tempTabu.bigNum +] ]; change2 = Distance[ solution[tempTabu.smallNum -] ][ solution[tempTabu.bigNum] ] +\ Distance[ solution[tempTabu.bigNum] ][ solution[tempTabu.smallNum+] ] +\ Distance[ solution[tempTabu.bigNum-] ][ solution[ tempTabu.smallNum ] ]+\ Distance[ solution[tempTabu.smallNum] ][ solution[tempTabu.bigNum +] ]; return (change2 - change1); } } } /************************************************* **Function: Get2optSolution **Description: 得到1个2邻域解 将移动元素,及其导致路径的变化值 存储到移动表中 **Calls: Get2OptChangeDistance() **Called By: TSP() **Input: strSolve 解空间指针 motiontable 移动表指针 **Output: 无 **Return: void **Others: 随机数要注意! *************************************************/ void Get2optSolution(const StrSolve * strSolve,MotionTable *motiontable ) { //产生一个1-CityNum-1之间的随机数 因为默认0为初始位置 不能动 ElementType temp; ElementType changeDistance; int rand1,rand2; // rand1 = (CityNum-1) *rand()/(RAND_MAX + 1.0); rand1 = rand()%(CityNum-)+; rand2 = rand()%(CityNum-)+; while( rand2 == rand1 )//必须产生两个不同的随机数 切不能为0 rand2 = rand()%(CityNum-) +; //记录交换的两个元素 (不是位置) motiontable->tabu.smallNum = (rand2 >rand1)? rand1:rand2; motiontable->tabu.bigNum = (rand2 >rand1)? rand2:rand1; motiontable->changedistance = Get2OptChangeDistance( &motiontable->tabu ,strSolve->tempSolution ); } /************************************************* **Function: Insert_Sort **Description: 按从小到大排序 插入排序 将制定的类数组变量 的内容进行排序 **Calls: 无 **Called By: FindBestMotionValue() **Input: motiontable 移动表指针 n为类数组 元素个数 **Output: 无 **Return: void **Others: *************************************************/ void Insert_Sort (MotionTable * motiontable,int n) { //进行N-1轮插入过程 int i,k; ; i<n; i++){ //首先找到元素a[i]需要插入的位置 ; while( (motiontable[j].changedistance < motiontable[i].changedistance ) && (j <i ) ) j++; //将元素插入到正确的位置 if(i != j){ //如果i==j,说明a[i]刚好在正确的位置 MotionTable temp = motiontable[i]; for(k = i; k > j; k--){ motiontable[k] = motiontable[k-]; } motiontable[j] = temp; } } } /************************************************* **Function: FindBestMotionValue **Description: 找到移动表中最小的值 即为最优值 **Calls: Insert_Sort() **Called By: TSP() **Input: motiontable 移动表指针 **Output: 无 **Return: MotionTable *型的指针 存储移动表中最好值的表格指针 **Others: *************************************************/ MotionTable * FindBestMotionValue( MotionTable * motiontable) { //下面是仅仅找到一个最好的值 不管在不在禁忌表中 // MotionTable *bestMotion= motiontable; // MotionTable *start = motiontable; // MotionTable *end = motiontable + Neighbor-1; // while(start++ < end ){ // if( start->changedistance < bestMotion->changedistance){ // bestMotion = start;//保存最好的结构 // } // } // if( start->changedistance < bestMotion->changedistance ) // bestMotion = start; // return bestMotion;//f返回最好结构的指针 Insert_Sort(motiontable,Neighbor);//选择排序算法 从小到大排 return motiontable;//返回最好元素的地址 } /************************************************* **Function: GetInitLevel **Description: 获取初始解的渴望水平 **Calls: **Called By: TSP() **Input: distance 存储城市的矩阵指针 initSolution 初始解指针 **Output: 无 **Return: 初始解的渴望水平 **Others: *************************************************/ int GetInitLevel( ElementType **distance,ElementType * initSolution) { int i; ; ; i < CityNum- ; i++){ SumLevel += distance[ initSolution[i] ][ initSolution[i+] ]; } SumLevel+= distance[ initSolution[i] ][];//最后在加上 最后一个值和初始值的 距离 才是循环的总距离距离 return SumLevel; } /************************************************* **Function: TSP **Description: TSP核心算法 **Calls: GetInitLevel() **Called By: TSP() Get2optSolution() FindBestMotionValue() UpdateTabu() FindPosition() memcpy() **Input: distance 存储城市的矩阵指针 solutionSpace 解空间指针 motiontable 移动表 desireLevel 渴望水平 queue 禁忌表队列指针 **Output: 最优解信息 **Return: void **Others: *************************************************/ void TSP( ElementType **distance, StrSolve * solutionSpace ,MotionTable *motiontable,int *desireLevel,Queue *queue) { int i; int temp; ; MotionTable * BestMotionStruct; ElementType BestChangeDistance;//最好的改变的值 // Init2Opt();//初始化相关 *desireLevel = GetInitLevel(distance,solutionSpace->initSolution); solutionSpace->lastdistance = *desireLevel;//初始最优值为上次移动的最好的距离 solutionSpace->initdistance = solutionSpace->lastdistance;//将初始值给初始距离 之后再判断 减少的距离 printf("初始距离:%d ",*desireLevel); // printf("初始最好的距离是%d,solutionSpace->lastdistance = %d\n",*desireLevel,solutionSpace->lastdistance); printf("城市数量:%d 迭代次数:%d 邻居个数:%d\n",CityNum,MaxNG,Neighbor); //迭代 次数作为停止条件 while( currentNG++ < MaxNG ){ //获得邻居最好解 ; neighborNum < Neighbor; neighborNum++ ){//循环Neighbor那么多次 Get2optSolution(SolutionSpace,&motionTable[neighborNum] );//将邻域 移动放在移动表中 } //找到移动表中最小的值 此时解若是 < 渴望水平 则更新最优解 否则找到不在禁忌表中的 最好的解 更新当前解 BestMotionStruct = FindBestMotionValue( motiontable); BestChangeDistance = BestMotionStruct->changedistance; if( solutionSpace->lastdistance + BestChangeDistance < *desireLevel){//当前迭代出的最好的解 小于渴望水平 更新最优解T表当前解 int temp; //更新T表 UpdateTabu(queue,&BestMotionStruct->tabu); //更新渴望水平 *desireLevel = solutionSpace->lastdistance +BestChangeDistance; //更新上次迭代的最优值 solutionSpace->lastdistance = *desireLevel; //更新当前解和最优解 FindPosition(solutionSpace->tempSolution,&BestMotionStruct->tabu);//找到当前解 对应的解空间的位置 temp = solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum ]; solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum] = solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ]; solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ] = temp; memcpy( solutionSpace->currentSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间 memcpy( solutionSpace->optimalSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum ); } else{//没有小于渴望水平 找到不在禁忌表中最好的移动 //在移动表中找到不在禁忌表中最好元素 因为拍好序了 所以从表的第二个值开始找即可 int i; ;i< Neighbor; i++){ if( !IsFindTabu(queue,&motiontable[i].tabu) ){ int temp; //不在禁忌表中 则这个值就是目前来说最好的值 BestMotionStruct = &motiontable[i]; //更新T表 UpdateTabu(queue,&BestMotionStruct->tabu); solutionSpace->lastdistance = solutionSpace->lastdistance + BestMotionStruct->changedistance; //更新当前解 FindPosition(solutionSpace->tempSolution,&BestMotionStruct->tabu);//找到当前解 对应的解空间的位置 temp = solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum ]; solutionSpace->tempSolution[ BestMotionStruct->tabu.smallNum] = solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ]; solutionSpace->tempSolution[ BestMotionStruct->tabu.bigNum ] = temp; memcpy( solutionSpace->currentSolution,solutionSpace->tempSolution,sizeof(ElementType)*CityNum ); //将临时解空间值复制到当前解空间 break;//跳出循环 } } } } currentNG = ;//将全局迭代次数变量值清零 printf("\n初始值:%d 最优解值:%d 优化距离:%d\n最优解元素:\n\n",\ solutionSpace->initdistance,\ GetInitLevel(distance,solutionSpace->optimalSolution),solutionSpace->initdistance - *desireLevel); ;i< CityNum;i++){ printf("%d-> ",solutionSpace->optimalSolution[i]); } printf( ] ); }
原创:TSP问题解决方案-----禁忌搜索算法C实现的更多相关文章
- 禁忌搜索算法TSA 旅行商问题TSP python
import math import random import numpy as np import matplotlib.pyplot as plt from mpl_toolkits.mplot ...
- 【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
01 什么是禁忌搜索算法? 1.1 先从爬山算法说起 爬山算法从当前的节点开始,和周围的邻居节点的值进行比较. 如果当前节点是最大的,那么返回当前节点,作为最大值 (既山峰最高点):反之就用最高的邻居 ...
- 【高级算法】禁忌搜索算法解决3SAT问题(C++实现)
转载请注明出处:http://blog.csdn.net/zhoubin1992/article/details/46440389 近期梳理,翻出了当年高级算法课程做的题目.禁忌搜索算法解决3SAT问 ...
- 原创:工作指派问题解决方案---模拟退火算法C实现
本文忽略了对于模拟退火的算法的理论讲解,读者可参考相关的博文或者其他相关资料,本文着重于算法的实现: /************************************************ ...
- 【原创】BI解决方案选型之ETL数据整合工具对比
一.背景 在企业BI平台建设过程中,数据整合始终是一切的基础,简单BI项目可以通过存储过程来实现,而复杂.全面.多方异构数据来源等就大大增加了复杂性,存储过程的可管理性.可维护性.容错性等就无法很好的 ...
- 【智能算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细解析和TSP代码实例以及01背包代码实例
喜欢的话可以扫码关注我们的公众号哦,更多精彩尽在微信公众号[程序猿声] 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部搜索科普三连 虽然之前做的很多篇启发式的算法都有跟大家提过局部 ...
- 智能优化算法对TSP问题的求解研究
要求: TSP 算法(Traveling Salesman Problem)是指给定 n 个城市和各个城市之间的距离,要 求确定一条经过各个城市当且仅当一次的最短路径,它是一种典型的优化组合问题,其最 ...
- 模拟退火算法SA原理及python、java、php、c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径
模拟退火算法SA原理及python.java.php.c++语言代码实现TSP旅行商问题,智能优化算法,随机寻优算法,全局最短路径 模拟退火算法(Simulated Annealing,SA)最早的思 ...
- 【算法】变邻域搜索算法(Variable Neighborhood Search,VNS)超详细一看就懂的解析
更多精彩尽在微信公众号[程序猿声] 变邻域搜索算法(Variable Neighborhood Search,VNS)一看就懂的解析 00 目录 局部搜索再次科普 变邻域搜索 造轮子写代码 01 局部 ...
随机推荐
- 阿里 java学习之路
https://maimai.cn/article/detail?fid=96107193&push_id=5603&share_user=http%3A%2F%2Fi9.taou.c ...
- spi master接口的fpga实现
前言 当你器件的引脚贼少的时候,需要主机和从机通信,spi就派上了用场,它可以一对多,但只是片选到的从机能和主机通信,其他的挂机. spi:serial peripheral interface 串行 ...
- Bootstrap-table事件使用
HTML <div class="alert alert-danger" id="eventInfo"></div> <table ...
- 在centos6上实现编译安装lamp和wordpress,并编译xcache
author:JevonWei 版权声明:原创作品 软件环境: centos6.9 httpd-2.4.27.tar.bz2 apr-1.5.2.tar.bz2 apr-util-1.5.4.tar. ...
- maven 自我学习笔记
1.常用网站: maven.apache.org http://mvnrepository.com/ 2.命令 mvn -v 查看maven的版本 mvn -compile 在项目的根目录下编译项 ...
- poj 1882完全背包变形
题意:给出一个上限硬币数量s,给出n套硬币价值,求一套硬币能用不大于s数量的硬币组成从1开始连续的区间价值,其中,如果其最大值相同,输出数量小的和价值小的. 思路:很明显的完全背包,纠结后面最大值相同 ...
- poj 1948二维01背包
题意:给出不多于40个小棍的长度,求出用所有小棍组成的三角形的最大面积. 思路:三角形3边求面积,海伦公式:p=(a+b+c)/2;S=p*(p-a)*(p-b)*(p-c);因为最大周长为1600 ...
- js page click
DataTables Editor Your account: Login / Register Examples Manual Reference Options API Events Butt ...
- js 实现 input type="file" 文件上传示例代码
在开发中,文件上传必不可少但是它长得又丑.浏览的字样不能换,一般会让其隐藏点其他的标签(图片等)来时实现选择文件上传功能 在开发中,文件上传必不可少,<input type="file ...
- Linux下undefined reference to ‘pthread_create’问题解决
Linux下undefined reference to 'pthread_create'问题解决 在试用Linux 线程模块时,试用pthread_create 函数. 编译命令为 gcc main ...