赋权边覆盖问题——采用禁忌搜索算法的C++实现
赋权边覆盖问题是图论中的经典问题。
本文详细讨论了禁忌搜索算法求解赋权边覆盖问题的定义、原理及求解思路,在文末给出了实验结果及完整的C++实现代码。
///
///
源程序
(一)最小边覆盖
#include "stdafx.h"#include<iostream> using namespace std;/控制参数 #define EDGE_NUM 7 //边数量 #define POINT_NUM 6 //顶点数量 #define N_K 2 //K邻域 #define HNUM 4 //禁忌队列长度,队列元素为一可行解对象static int stepMAX=50;//最大迭代次数,终止条件 static float GOAL=100;//最优目标值 /主要数据结构定义/ struct EDGE { int from;//边起始顶点序号 int to;//边终止顶点序号 float w;//边的权值 };//边结构体数据类型static EDGE elib[EDGE_NUM ];//边数据存储数组 static int plib[POINT_NUM];//顶点序号数据存储数组 static int leb[POINT_NUM ];//顶点覆盖标志数组class vectorE { public:int e[EDGE_NUM];//解向量中各边是否被选种标志 int i,j;vectorE(int a[]){for (i=0;i<EDGE_NUM;i++)e[i]=a[i];}vectorE(){for (i=0;i<EDGE_NUM;i++)e[i]=-1;//默认参数下,解向量是非法的标志-1}vectorE(vectorE & VE){for (i=0;i<EDGE_NUM;i++)e[i]=VE.e[i];}int operator==(vectorE VE)//运算符重载{for (i=0,j=0;i<EDGE_NUM;i++){if (e[i]!=VE.e[i])break; else j+=1;}if(j==EDGE_NUM)return 1;else return 0;}void operator=(vectorE VE)//运算符重载{for (i=0;i<EDGE_NUM;i++)e[i]=VE.e[i];}void operator=(int a[])//运算符重载{for (i=0;i<EDGE_NUM;i++)e[i]=a[i];} vectorE operator-(vectorE VE)运算符重载,返回邻居 {vectorE et=e;for (i=0;i<EDGE_NUM;i++){if (VE.e[i]==1)et.e[i]=1-e[i]; } return et; }float WE() { float wt=0; for (i=0;i<EDGE_NUM;i++) { wt+=e[i]*elib[i].w; } return abs(wt); } };//可行解类static vectorE H[HNUM];//禁忌队列 static H_rear=HNUM;//禁忌队列对尾指针 static H_front=HNUM;//禁忌队列对头指针 static H_s=0;//禁忌队列满标志struct N_TABE//邻域索引表结构 {vectorE ve;struct N_TABE * next; };///禁忌队列操作函数 void H_clear()//禁忌队列初始化 { vectorE ve;//非法解 int i; for (i=0;i<HNUM;i++)H[i]=ve;//初始化队列元素, H_rear=HNUM;//禁忌队列对尾指针 H_front=HNUM;//禁忌队列对头指针 H_s=0;//禁忌队列满标志 }bool H_add( vectorE ve)//入队运算 {if ((H_s==1)&&(H_front==H_rear)){cout<<"队列已满,无法插入!"<<endl;return false;} H_rear+=1; if (H_rear==HNUM+1)H_rear=1; H[H_rear-1]=ve; H_s=1;//禁忌队列满标志 return true; }bool H_delete( vectorE & ve)//出队运算,有参数 {vectorE ve_t;//非法解if ((H_s==0)&&(H_front==H_rear)){cout<<"队列已空,无法删除!"<<endl;return false;} H_front+=1; if (H_front==HNUM+1)H_front=1; ve=H[H_front-1]; H[H_front-1]=ve_t;if (H_front==H_rear)H_s=0; return true; }bool H_delete( )//出队运算重载,无参数 {vectorE ve_t;//非法解if ((H_s==0)&&(H_front==H_rear)){cout<<"队列已空,无法删除!"<<endl;return false;} H_front+=1; if (H_front==HNUM+1)H_front=1; //ve=H[H_front-1]; H[H_front-1]=ve_t; if (H_front==H_rear)H_s=0; return true; }int H_IsNot(vectorE ve)//测试解对象ve是否在禁忌队列中,若在,返回在队列中的序号,如不在,返回-1 {int i=H_front+1;if (i==HNUM+1)i=1;if ((H_s==0)&&(H_front==H_rear))return -1;else if (i>H_rear){for (;i<=HNUM;i++){if (H[i-1]==ve) return i;}for (i=1;i<=H_rear;i++){if (H[i-1]==ve) return i;}}else{for (;i<=H_rear;i++){if (H[i-1]==ve) return i;}}return -1; }void H_free(int n)//特赦禁忌队列中序号为n的元素 { int i; vectorE ve_t;//非法解 if ((n<0)||(n>HNUM)) { cout<<"序号非法,不存在特赦元素!"<<endl;return; }if ((H_s==0)&&(H_front==H_rear)){cout<<"队列为空,不存在特赦元素!"<<endl;return;}if( ((H_front+1)% HNUM)==n) //如果特赦元素为排头元素{H_front+=1;if (H_front==HNUM+1)H_front=1; //ve=H[H_front-1];H[H_front-1]=ve_t;if (H_front==H_rear)H_s=0;}//如果特赦元素为排头元素else if( H_rear==n) //如果特赦元素为对尾元素{H[H_rear-1]=ve_t;H_rear-=1;if (H_rear==0)H_rear=HNUM;if (H_front==H_rear)H_s=0;}//如果特赦元素为排头元素else{if (n>H_rear){for (i=n;i<=HNUM-1;i++) {H[i-1]=H[i];}H[HNUM-1]=H[0];for (i=1;i<H_rear-1;i++){H[i-1]=H[i];}H_rear-=1;if (H_rear==0)H_rear=HNUM;}else{for (i=n;i<=H_rear-1;i++) {H[i-1]=H[i];}H_rear-=1;if (H_rear==0)H_rear=HNUM;}} }void H_display()//禁忌对队列显示,用于调试程序 {int i,j,a,b;if ((H_s==0)&&(H_front==H_rear)){cout<<"队列为空,无法显示!"<<endl;return ;}else{a=H_front+1;if (a==HNUM+1)a=1;b=H_rear;if (a>b){for (i=a;i<=HNUM;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;} for (i=1;i<=H_rear;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;}}else{for (i=a;i<=b;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;}}cout<<"H_front,H_rear,H_s are:"<<H_front<<","<<H_rear<<","<<H_s<<endl;}}/辅助子函数/// void Edge_Point_initial()//边、顶点数据初始化 { int i; for (i=0;i<POINT_NUM;i++)plib[i]=i;//顶点序号赋初值elib[0].from=0; elib[0].to=1; elib[0].w=1;//第0条边数据elib[1].from=0; elib[1].to=2; elib[1].w=1;//第1条边数据elib[2].from=1; elib[2].to=2; elib[2].w=1;//第2条边数据elib[3].from=1; elib[3].to=4; elib[3].w=1;//第3条边数据elib[4].from=1; elib[4].to=3; elib[4].w=1;//第4条边数据elib[5].from=2; elib[5].to=5; elib[5].w=1;//第5条边数据elib[6].from=2; elib[6].to=4; elib[6].w=1;//第6条边数据}void lebset() //顶点覆盖标志数组置1 { int i; for (i=0;i<POINT_NUM;i++)leb[i]=1;}int lebtest()//顶点覆盖标志数组累加测试 { int i,j; for (i=0,j=0;i<POINT_NUM;i++)j+=leb[i]; if (j==0) return 0; else return 1;}int fugaitest(vectorE E)//测试解对象是否为可行解,即是否为覆盖,返回值:1000,非覆盖;其它,覆盖数 { int i,j,sum; lebset();顶点覆盖标志数组置1 for (i=0,sum=0;i<EDGE_NUM;i++) { if (E.e[i]==1)//如果该边被选中,则其顶点标志置0 {sum+=1;leb[elib[i].from]=0;leb[elib[i].to]=0; } } j=lebtest(); lebset();顶点覆盖标志数组置1 if (j==0) return sum; else return 1000; }N_TABE* N_tableCreate( )//邻域辅助索引链表构造 { int kmax=(1<<EDGE_NUM)-1; int i,j,n,t; int a[EDGE_NUM]; N_TABE*top=NULL,* p=NULL,*q=NULL;for (n=1;n<=kmax;n++) {for (i=0;i<EDGE_NUM;i++)a[i]=0;for (i=0,t=0,j=n;i<EDGE_NUM;i++){a[EDGE_NUM-i-1]=j%2;t+=a[EDGE_NUM-i-1];j=j>>1;}if ((t>=1)&&(t<=N_K))//{q=new N_TABE;q->next=NULL;q->ve=a;if (top==NULL){top=q;p=q;}else{p->next=q;p=q;}}} return top;}//主控制函数// void main ( ) {Edge_Point_initial();//边、顶点数据初始化 H_clear();//禁忌队列初始化,队列为空 int e0[]={1,1,1,1,1,1,1}; vectorE E0=e0;//并初始化解对象 vectorE Et; vectorE Ebest=E0;//最优解赋初值 vectorE Enow=E0;//当前覆盖 int F_min=fugaitest(E0);//最小覆盖数赋初值 int F_now=F_min;//最小覆盖数赋初值 int i,j,step,k,t;N_TABE *N_head=N_tableCreate( );//邻域辅助索引表构造 N_TABE *p=N_head;//工作指针vectorE Enowbest,Enowbest0;//当前跌代最优解 int F_nowmin=fugaitest(Enowbest);//当前跌代最小覆盖数赋初值 int enow[]={0,0,0,0,0,0,0};//当前跌代后选解最优解初值 H_add( Enow);//禁忌表队列赋初值cout<<"当前最优解:";for (i=0;i<EDGE_NUM;i++) {if (Enow.e[i]==1){ cout<<"("<<elib[i].from<<","<<elib[i].to<<"),";}else{cout<<"(-,-),";}} cout<<"--,";cout<<"当前最小覆盖数:"<<F_min<<endl;for (step=0;step<stepMAX;step++) {Enowbest=enow;Enowbest0=Enowbest;//用于比较初值是否变化F_nowmin=fugaitest(Enowbest);//当前跌代最小覆盖数赋初值//当前跌代最小覆盖数赋初值 // p=N_head; while(p->next!=NULL)//遍历K-邻域所有邻居 {Et=Enow-p->ve;//当前边选择组合,满足K条边距离要求,但还未证实为覆盖p=p->next;//立即更新p指针t=fugaitest(Et);//覆盖数if (t==1000) //不满足覆盖要求,Et不是E0 K-邻居{continue;}else //满足覆盖要求,Et是E0 K-邻居{if (H_IsNot(Et)==-1)//最优且不在禁忌表中{if (Enowbest==Enowbest0){Enowbest=Et;F_nowmin=t;}else{if (t<F_nowmin){Enowbest=Et;F_nowmin=t;cout<<"当前最优解:";for (i=0;i<EDGE_NUM;i++){if (Enowbest.e[i]==1){ cout<<"("<<elib[i].from<<","<<elib[i].to<<"),";}else{cout<<"(-,-),";}}cout<<"--,";cout<<"当前最小覆盖数:"<<F_nowmin<<endl;}}}}}if (Enowbest==Enowbest0)//无侯选解,特赦// {p=N_head;while(p->next!=NULL)//遍历K-邻域所有邻居{Et=Enow-p->ve;//当前边选择组合,满足K条边距离要求,但还未证实为覆盖p=p->next;//立即更新p指针t=fugaitest(Et);if (t==1000) //不满足覆盖要求,Et不是E0 K-邻居{continue;}else //满足覆盖要求,Et是E0 K-邻居{if (Enowbest==Enowbest0){Enowbest=Et;F_nowmin=t;}else{if (t<F_nowmin){Enowbest=Et;F_nowmin=t;}}} }if (Enowbest==Enowbest0){break;}else//如果在禁忌表中有当前次跌代,特赦当前次跌代的解向量{t= H_IsNot(Enowbest);H_free(t);Enow=Enowbest;//更新当前解}} else {if (F_nowmin<F_min){Ebest=Enowbest;F_min=F_nowmin;//记忆最优解}Enow=Enowbest;//更新当前解if ((H_s==1)&&(H_front==H_rear))H_delete( );//如果队列满,清除排头H_add( Enow);//更新禁忌表}}//迭代循环cout<<endl<<"全局最优解:"; for (i=0;i<EDGE_NUM;i++) { if (Ebest.e[i]==1) { cout<<"("<<elib[i].from<<","<<elib[i].to<<"),"; }} cout<<"--,"; cout<<"全局最小覆盖数:"<<F_min<<endl;delete [] N_head;}
(二)赋权边覆盖:
#include "stdafx.h"#include<iostream> using namespace std;/控制参数 #define EDGE_NUM 7 //边数量 #define POINT_NUM 6 //顶点数量 #define N_K 2 //K邻域 #define HNUM 4 //禁忌队列长度,队列元素为一可行解对象static int stepMAX=50;//最大迭代次数,终止条件 static float GOAL=100;//最优目标值 /主要数据结构定义/ struct EDGE { float w;//边的权值 int from;//边起始顶点序号 int to;//边终止顶点序号};//边结构体数据类型static EDGE elib[EDGE_NUM ];//边数据存储数组 static int plib[POINT_NUM];//顶点序号数据存储数组 static int leb[POINT_NUM ];//顶点覆盖标志数组class vectorE { public:int e[EDGE_NUM];//解向量中各边是否被选种标志 int i,j;vectorE(int a[]){for (i=0;i<EDGE_NUM;i++)e[i]=a[i];}vectorE(){for (i=0;i<EDGE_NUM;i++)e[i]=-1;//默认参数下,解向量是非法的标志-1}vectorE(vectorE & VE){for (i=0;i<EDGE_NUM;i++)e[i]=VE.e[i];}int operator==(vectorE VE)//运算符重载{for (i=0,j=0;i<EDGE_NUM;i++){if (e[i]!=VE.e[i])break; else j+=1;}if(j==EDGE_NUM)return 1;else return 0;}void operator=(vectorE VE)//运算符重载{for (i=0;i<EDGE_NUM;i++)e[i]=VE.e[i];}void operator=(int a[])//运算符重载{for (i=0;i<EDGE_NUM;i++)e[i]=a[i];} vectorE operator-(vectorE VE)运算符重载,返回邻居 {vectorE et=e;for (i=0;i<EDGE_NUM;i++){if (VE.e[i]==1)et.e[i]=1-e[i]; } return et; }float WE() { float wt=0.0; for (i=0;i<EDGE_NUM;i++) { wt+=double(e[i])*elib[i].w; } return wt>0?wt:-wt; } };//可行解类static vectorE H[HNUM];//禁忌队列 static H_rear=HNUM;//禁忌队列对尾指针 static H_front=HNUM;//禁忌队列对头指针 static H_s=0;//禁忌队列满标志struct N_TABE//邻域索引表结构 {vectorE ve;struct N_TABE * next; };///禁忌队列操作函数 void H_clear()//禁忌队列初始化 { vectorE ve;//非法解 int i; for (i=0;i<HNUM;i++)H[i]=ve;//初始化队列元素, H_rear=HNUM;//禁忌队列对尾指针 H_front=HNUM;//禁忌队列对头指针 H_s=0;//禁忌队列满标志 }bool H_add( vectorE ve)//入队运算 {if ((H_s==1)&&(H_front==H_rear)){cout<<"队列已满,无法插入!"<<endl;return false;} H_rear+=1; if (H_rear==HNUM+1)H_rear=1; H[H_rear-1]=ve; H_s=1;//禁忌队列满标志 return true; }bool H_delete( vectorE & ve)//出队运算,有参数 {vectorE ve_t;//非法解if ((H_s==0)&&(H_front==H_rear)){cout<<"队列已空,无法删除!"<<endl;return false;} H_front+=1; if (H_front==HNUM+1)H_front=1; ve=H[H_front-1]; H[H_front-1]=ve_t;if (H_front==H_rear)H_s=0; return true; }bool H_delete( )//出队运算重载,无参数 {vectorE ve_t;//非法解if ((H_s==0)&&(H_front==H_rear)){cout<<"队列已空,无法删除!"<<endl;return false;} H_front+=1; if (H_front==HNUM+1)H_front=1; //ve=H[H_front-1]; H[H_front-1]=ve_t; if (H_front==H_rear)H_s=0; return true; }int H_IsNot(vectorE ve)//测试解对象ve是否在禁忌队列中,若在,返回在队列中的序号,如不在,返回-1 {int i=H_front+1;if (i==HNUM+1)i=1;if ((H_s==0)&&(H_front==H_rear))return -1;else if (i>H_rear){for (;i<=HNUM;i++){if (H[i-1]==ve) return i;}for (i=1;i<=H_rear;i++){if (H[i-1]==ve) return i;}}else{for (;i<=H_rear;i++){if (H[i-1]==ve) return i;}}return -1; }void H_free(int n)//特赦禁忌队列中序号为n的元素 { int i; vectorE ve_t;//非法解 if ((n<0)||(n>HNUM)) { cout<<"序号非法,不存在特赦元素!"<<endl;return; }if ((H_s==0)&&(H_front==H_rear)){cout<<"队列为空,不存在特赦元素!"<<endl;return;}if( ((H_front+1)% HNUM)==n) //如果特赦元素为排头元素{H_front+=1;if (H_front==HNUM+1)H_front=1; //ve=H[H_front-1];H[H_front-1]=ve_t;if (H_front==H_rear)H_s=0;}//如果特赦元素为排头元素else if( H_rear==n) //如果特赦元素为对尾元素{H[H_rear-1]=ve_t;H_rear-=1;if (H_rear==0)H_rear=HNUM;if (H_front==H_rear)H_s=0;}//如果特赦元素为排头元素else{if (n>H_rear){for (i=n;i<=HNUM-1;i++) {H[i-1]=H[i];}H[HNUM-1]=H[0];for (i=1;i<H_rear-1;i++){H[i-1]=H[i];}H_rear-=1;if (H_rear==0)H_rear=HNUM;}else{for (i=n;i<=H_rear-1;i++) {H[i-1]=H[i];}H_rear-=1;if (H_rear==0)H_rear=HNUM;}} }void H_display()//禁忌对队列显示,用于调试程序 {int i,j,a,b;if ((H_s==0)&&(H_front==H_rear)){cout<<"队列为空,无法显示!"<<endl;return ;}else{a=H_front+1;if (a==HNUM+1)a=1;b=H_rear;if (a>b){for (i=a;i<=HNUM;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;} for (i=1;i<=H_rear;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;}}else{for (i=a;i<=b;i++){for(j=0;j<EDGE_NUM;j++)cout<<H[i-1].e[j]<<",";cout<<endl;}}cout<<"H_front,H_rear,H_s are:"<<H_front<<","<<H_rear<<","<<H_s<<endl;}}/辅助子函数/// void Edge_Point_initial()//边、顶点数据初始化 { int i; for (i=0;i<POINT_NUM;i++)plib[i]=i;//顶点序号赋初值elib[0].from=0; elib[0].to=1; elib[0].w=0.2;//第0条边数据elib[1].from=0; elib[1].to=2; elib[1].w=1.3;//第1条边数据elib[2].from=1; elib[2].to=2; elib[2].w=2.4;//第2条边数据elib[3].from=1; elib[3].to=4; elib[3].w=2;//第3条边数据elib[4].from=1; elib[4].to=3; elib[4].w=0.1;//第4条边数据elib[5].from=2; elib[5].to=5; elib[5].w=1;//第5条边数据elib[6].from=2; elib[6].to=4; elib[6].w=1.4;//第6条边数据}void lebset() //顶点覆盖标志数组置1 { int i; for (i=0;i<POINT_NUM;i++)leb[i]=1;}int lebtest()//顶点覆盖标志数组累加测试 { int i,j; for (i=0,j=0;i<POINT_NUM;i++)j+=leb[i]; if (j==0) return 0; else return 1;}int fugaitest(vectorE E)//测试解对象是否为可行解,即是否为覆盖,返回值:1000,非覆盖;其它,覆盖数 { int i,j,sum; lebset();顶点覆盖标志数组置1 for (i=0,sum=0;i<EDGE_NUM;i++) { if (E.e[i]==1)//如果该边被选中,则其顶点标志置0 {sum+=1;leb[elib[i].from]=0;leb[elib[i].to]=0; } } j=lebtest(); lebset();顶点覆盖标志数组置1 if (j==0) return sum; else return 1000; }N_TABE* N_tableCreate( )//邻域辅助索引链表构造 { int kmax=(1<<EDGE_NUM)-1; int i,j,n,t; int a[EDGE_NUM]; N_TABE*top=NULL,* p=NULL,*q=NULL;for (n=1;n<=kmax;n++) {for (i=0;i<EDGE_NUM;i++)a[i]=0;for (i=0,t=0,j=n;i<EDGE_NUM;i++){a[EDGE_NUM-i-1]=j%2;t+=a[EDGE_NUM-i-1];j=j>>1;}if ((t>=1)&&(t<=N_K))//{q=new N_TABE;q->next=NULL;q->ve=a;if (top==NULL){top=q;p=q;}else{p->next=q;p=q;}}} return top;}//主控制函数// void main ( ) {Edge_Point_initial();//边、顶点数据初始化 H_clear();//禁忌队列初始化,队列为空 int e0[]={1,1,1,1,1,1,1}; vectorE E0=e0;//并初始化解对象 vectorE Et; vectorE Ebest=E0;//最优解赋权赋初值 vectorE Enow=E0;//当前覆盖 float F_min= Enow.WE();//最小赋权覆盖数赋初值 float F_now=F_min;//最小赋权覆盖数赋初值 int i,j,step,k,t;N_TABE *N_head=N_tableCreate( );//邻域辅助索引表构造 N_TABE *p=N_head;//工作指针vectorE Enowbest,Enowbest0;//当前跌代最优解 float F_nowmin=Enowbest.WE();//当前跌代最小覆盖数赋初值 int enow[]={0,0,0,0,0,0,0};//当前跌代后选解最优解初值 H_add( Enow);//禁忌表队列赋初值cout<<"当前最优解:";for (i=0;i<EDGE_NUM;i++) {if (Enow.e[i]==1){ cout<<"("<<elib[i].from<<","<<elib[i].to<<"),";}else{cout<<"(-,-),";}} cout<<"--,";cout<<"当前最小赋权值:"<<F_min <<endl;for (step=0;step<stepMAX;step++) {Enowbest=enow;Enowbest0=Enowbest;//用于比较初值是否变化F_nowmin=Enowbest.WE();//当前跌代最小覆盖数赋初值//当前跌代最小覆盖数赋初值 // p=N_head; while(p->next!=NULL)//遍历K-邻域所有邻居 {Et=Enow-p->ve;//当前边选择组合,满足K条边距离要求,但还未证实为覆盖p=p->next;//立即更新p指针t=fugaitest(Et);//覆盖数if (t==1000) //不满足覆盖要求,Et不是E0 K-邻居{continue;}else //满足覆盖要求,Et是E0 K-邻居{if (H_IsNot(Et)==-1)//最优且不在禁忌表中{if (Enowbest==Enowbest0){Enowbest=Et;F_nowmin=Enowbest.WE();}else{if (Et.WE()<F_nowmin){Enowbest=Et;F_nowmin=Et.WE();cout<<"当前最优解:";for (i=0;i<EDGE_NUM;i++){if (Enowbest.e[i]==1){ cout<<"("<<elib[i].from<<","<<elib[i].to<<"),";}else{cout<<"(-,-),";}}cout<<"--,";cout<<"当前最小赋权值:"<<F_nowmin<<endl;}}}}}if (Enowbest==Enowbest0)//无侯选解,特赦// {p=N_head;while(p->next!=NULL)//遍历K-邻域所有邻居{Et=Enow-p->ve;//当前边选择组合,满足K条边距离要求,但还未证实为覆盖p=p->next;//立即更新p指针t=fugaitest(Et);if (t==1000) //不满足覆盖要求,Et不是E0 K-邻居{continue;}else //满足覆盖要求,Et是E0 K-邻居{if (Enowbest==Enowbest0){Enowbest=Et;F_nowmin=t;}else{if (Et.WE()<F_nowmin){Enowbest=Et;F_nowmin=Et.WE();}}} }if (Enowbest==Enowbest0){break;//跌代终止}else//如果在禁忌表中有当前次跌代,特赦当前次跌代的解向量{t= H_IsNot(Enowbest);H_free(t);Enow=Enowbest;//更新当前解}} else {if (F_nowmin<F_min){Ebest=Enowbest;F_min=F_nowmin;//记忆最优解}Enow=Enowbest;//更新当前解if ((H_s==1)&&(H_front==H_rear))H_delete( );//如果队列满,清除排头H_add( Enow);//更新禁忌表}}//迭代循环cout<<endl<<"全局最优解:"; for (i=0;i<EDGE_NUM;i++) { if (Ebest.e[i]==1) { cout<<"("<<elib[i].from<<","<<elib[i].to<<"),"; }} cout<<"--,"; cout<<"全局最小赋权值:"<<F_min<<endl;delete [] N_head;}
赋权边覆盖问题——采用禁忌搜索算法的C++实现相关推荐
- 禁忌搜索算法(TABU)解决路线规划问题(CVRP)
文章目录 禁忌搜索算法解决路线规划问题 问题定义 CVRP问题解决算法 禁忌搜索算法 局部搜索的两种策略 局部搜索的缺点 禁忌搜索算法的提出 禁忌搜索算法流程图 禁忌搜索算法伪码 算法结果 统计结果 ...
- 【算法】禁忌搜索算法(Tabu Search,TS)超详细通俗解析附C++代码实例
01 什么是禁忌搜索算法? 1.1 先从爬山算法说起 爬山算法从当前的节点开始,和周围的邻居节点的值进行比较. 如果当前节点是最大的,那么返回当前节点,作为最大值 (既山峰最高点):反之就用最高的邻居 ...
- 组合赋权法之python
目录 1.简介 2.算法原理 2.1 指标正向化 2.2 数据标准化 2.3 计算主观权重 2.4 计算客观权重 2.5 计算组合权重 2.6 计算的得分 3.实例分析 3.1 读取数据 3.2 指标 ...
- 组合赋权法之matlab
目录 1.简介 2.算法原理 2.1 指标正向化 2.2 数据标准化 2.3 计算主观权重 2.4 计算客观权重 2.5 计算组合权重 2.6 计算的得分 3.实例分析 3.1 读取数据 3.2 指标 ...
- 基于禁忌搜索算法的三维装箱问题
装箱问题 装箱问题是复杂的离散组合最优化问题.所谓组合优化,是指在离散的.有限的数学结构上,寻找一个满足给定条件,并使其目标函数值达到最大或最小的解.经典的装箱问题要求把一定数量的物品放入容量相同的一 ...
- 基于禁忌搜索算法的TSP问题求解matlab仿真
目录 1.算法概述 2.仿真效果 3.matlab仿真源码 1.算法概述 禁忌搜索(Tabu Search,TS)算法是组合优化算法的一种,是局部搜索算法的扩展.禁忌搜索算法是人工智能在组合优化算法中 ...
- 【优化布局】matlab基于禁忌搜索算法求解基站选址问题代码
1 简介 物流配送中心选址问题在物流网络规划中占有非常重要的地位,选址的合理与否直接关系到配送中心未来的发展.针对企业选址的一般要求,以配送中心总成本最小为目标,构造了一种物流配送中心选址模型.该模型 ...
- 禁忌搜索算法求解TSP旅行商问题Matlab实现
一. 禁忌搜索算法 禁忌搜索算法是一种全局性邻域搜索算法,模拟人类具有记忆功能的寻优特征.它通过局部邻域搜索机制和相应的禁忌准则来避免迂回搜索,并通过破禁水平来释放一些被禁忌的优良状态,进而保证多样化 ...
- 【优化规划】基于matlab禁忌搜索算法求解配电网无功补偿优化规划问题【含Matlab源码 1842期】
一.基于禁忌搜索算法的无功优化参数选择及流程 禁忌搜索方法是Glover F在1986年首次提出的一种智能启发式算法.鉴于禁忌搜索算法是对局部邻域搜索的一种扩展,通过引入一个灵活的存储结构和相应的禁忌 ...
最新文章
- 030_jdbc-mysql事务
- Centos(阿里云) 安装python3.4以及pip3
- Intellij Idea导出可执行的jar包
- 聊天机器人突然火了,能解决那方面的需求吗?
- 如何使用vue组件搭建网页并打包发布
- JavaScript执行bat文件清理浏览器缓存
- ~~队列(数据结构)(附模板题 AcWing 829. 模拟队列)
- ant design pro模板_ant design pro 当中改变ant design 组件的样式和 数据管理
- 日常工作中,个人总结的 - Git - 常用操作方法 (三)
- python生成excel模板_使用python创建excel表格 --- XlsxWriter模板详解
- 查看.pth文件里面保存了哪些权重及那些权重的shape
- JAVA 使用SSH/springboot集成 CXF框架发布Webservice
- 小猪短租住房信息爬取
- 950个织梦网dede模板源码
- php 插件推荐,Typecho实用插件推荐(一)
- Java解决上台阶问题
- TransactionScope使用(二)——msdtc不可用
- PEP8风格是什么?
- Unity 颜色查找表富文本颜色
- java飞鸽源码_java版本的飞鸽编写(一)
热门文章
- DELPHI 线程类
- html z-index不显示,CSS3关于z-index不生效问题的解决
- 【c++中内存拷贝函数(C++ memcpy)详解】
- mysql查询姓张的同学_Mysql 基础2 (sql查询语句)
- WordPress优化教程大全
- echarts自定义区域地图
- 9.0 OTA升级logo不更新,输入法不更新
- 新年开工第一篇文章——推荐几个值得中小企业使用的ARM9/ARM11/Cortex A8处理器
- SpringCloud学习笔记(十二)基于Hystrix解决雪崩效应
- 二叉树的非递归遍历详解