赋权边覆盖问题——采用禁忌搜索算法的C++实现

 赋权边覆盖问题是图论中的经典问题。

本文详细讨论了禁忌搜索算法求解赋权边覆盖问题的定义、原理及求解思路,在文末给出了实验结果及完整的C++实现代码。

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第1张图片

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第2张图片

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第3张图片

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第4张图片

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第5张图片

赋权边覆盖问题——采用禁忌搜索算法的C++实现_第6张图片

///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////

源程序

(一)最小边覆盖

#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++实现)