關於一個應用分枝界限法解決最小頂點覆蓋問題的程序說明

 

//程序下載自:http://download.csdn.net/source/1930594

//頭文件Minheap.h

 

template <class Type>

class MinHeap                                        //最小堆類;

{

public:                             

MinHeap(Type a[], int n);                          //帶兩參數的構造函數,在此程序中沒有應用;

MinHeap(int ms);                                      //構造函數重載,只初始化堆的大小,對堆中結點不初始化;另外,堆元素的存儲是以數組

~MinHeap();                                             //形式,且無父、子指針,訪問父親結點,利用數組標號進行;

bool Insert(const Type &x);                       //插入堆中一個元素;

bool RemoveMin(Type &x);                          //刪除堆頂最小結點;

void MakeEmpty();                                              //使堆爲空

bool IsEmpty();

bool IsFull();

int Size();

protected:

void FilterDown(const int start, const int endOfHeap);                                  / /自頂向下構造堆

void FilterUp(const int start);                                                                        //自底向上構造堆

private:

Type *heap;                                                                 

int maxSize;

const int defaultSize;

int currentSize;                                                                                           //堆當前結點個數大小

};

 

template <class Type>

MinHeap<Type>::MinHeap(int ms):defaultSize(100)

{

maxSize=ms>defaultSize ? ms : defaultSize;

heap=new Type[maxSize];

currentSize=0;

}

 

template <class Type>

MinHeap<Type>::MinHeap(Type a[], int n):defaultSize(100)

{

maxSize=n>defaultSize ? n : defaultSize;

heap=new Type[maxSize];

currentSize=n;

for (int i=0; i<n; i++) heap[i]=a[i];

int curPos=(currentSize-2)/2;

while (curPos>=0)

{

   FilterDown(curPos, currentSize-1);

   curPos--;

}

}

 

template <class Type>

MinHeap<Type>::~MinHeap()

{

delete []heap;

}

 

template <class Type>

void MinHeap<Type>::FilterDown(const int start, const int endOfHeap)

{

int i=start, j=i*2+1;

Type temp=heap[i];

while (j<=endOfHeap)

{

   if (j<endOfHeap&&heap[j]>heap[j+1]) j++;                            

   if (temp<heap[j]) break;                        

   else

   {

    heap[i]=heap[j];

    i=j;

    j=2*i+1;

   }

}

heap[i]=temp;

}

 

template <class Type>

void MinHeap<Type>::FilterUp(const int start)

{

int i=start, j=(i-1)/2;

Type temp=heap[i];

while (i>0)

{

   if (temp>=heap[j]) break;

   else

   {

    heap[i]=heap[j];

    i=j;

    j=(i-1)/2;

   }

}

heap[i]=temp;

}

 

template <class Type>

bool MinHeap<Type>::RemoveMin(Type &x)

{

if (IsEmpty())

{

   cerr<<"Heap empty!"<<endl;

   return false;

}

x=heap[0];

heap[0]=heap[currentSize-1];

currentSize--;

FilterDown(0, currentSize-1);

return true;

}

 

template <class Type>

bool MinHeap<Type>::Insert(const Type &x)

{

if (IsFull())

{

   cerr<<"Heap Full!"<<endl;

        return false;

}

heap[currentSize]=x;

FilterUp(currentSize);

currentSize++;

return true;

}

 

template <class Type>

bool MinHeap<Type>::IsEmpty()

{

return currentSize==0;

}

 

template <class Type>

bool MinHeap<Type>::IsFull()

{

return currentSize==maxSize;

}

 

template <class Type>

void MinHeap<Type>::MakeEmpty()

{

currentSize=0;

}

 

template <class Type>

int MinHeap<Type>::Size()

{

return currentSize;

}

//MinCover.cpp
#include<iostream.h>
#include<fstream.h>
#include"MinHeap.h"
int *p;
//最小堆結點
class HeapNode                                                                 //堆結點類;
{
friend class VC;
public:
operator int()const{return cn;}                                       //重載運算符,比較兩個結點;
private:
   int i,cn,*x,*c;                                                          //i標示堆中結點號,cn標示當前加入的覆蓋頂點中權重之和,x數組標示那些                                                                                          //頂點加入了覆蓋頂點的行列,c數組標示X中的覆蓋頂點中所有的鄰接                                                                                            // 頂點;
                                                                                       
};
class VC                                                              // VC類用來對堆中結點內部的的操作,
{
friend MinCover(int **,int [],int);                          
private:
void BBVC();
bool cover(HeapNode E);
void AddLiveNode(MinHeap<HeapNode>&H,HeapNode E,int cn,int i,bool ch);
int **a,n,*w,*bestx,bestn;
};
void VC::BBVC()
{
MinHeap<HeapNode>H(100000);   //建立初始空堆;
HeapNode E;
E.x=new int[n+1];
E.c=new int[n+1];
for(int j=1;j<=n;j++)
{
   E.x[j]=E.c[j]=0;
}
int i=1,cn=0;  //開始時;
while(true)
{
   if(i>n)
   {
    if(cover(E))
    {
     for(int j=1;j<=n;j++)
      bestx[j]=E.x[j];
     bestn=cn;
     break;
    }
   }
   else
   {
    if(!cover(E))
     AddLiveNode(H,E,cn,i,true);                  //加入結點標號爲i 的結點到頂點覆蓋集中,並把更新後的結點再插入堆中;
    AddLiveNode(H,E,cn,i,false);                  //不把結點標號爲 i 的結點加入到頂點覆蓋集中,並把更新後的結點插入堆中;
   }
   if(H.IsEmpty())break;
   H.RemoveMin(E);                                   //把 堆頂點先移除給E; 
   cn=E.cn;
   i=E.i+1;                                                        
}
}
//cover
bool VC::cover(HeapNode E)
{
for(int j=1;j<=n;j++)
{
   if(E.x[j]==0&&E.c[j]==0)
    return false;        //存在任意一條邊的兩個頂點都爲0的情況下,爲未覆蓋情況;X[j]記錄覆蓋頂點,c[j]記錄與覆蓋頂點相連的頂點;
}                             //0表徵未覆蓋,1表徵已覆蓋;
return true;
}
void VC::AddLiveNode(MinHeap<HeapNode> &H,HeapNode E,int cn,int i,bool ch)
{
HeapNode N;
N.x=new int[n+1];
N.c=new int[n+1];
for(int j=1;j<=n;j++)
{
   N.x[j]=E.x[j];
   N.c[j]=E.c[j];
}
N.x[i]=ch?1:0;
if(ch)
{
   N.cn=cn+w[i];                                                     / /記錄I頂點是否加入覆蓋的行列中;
   for(int j=1;j<=n;j++)
    if(a[i][j]>0)                                                        //如果i,j相鄰,剛把j頂點加入覆蓋鄰接頂點集中;
     N.c[j]++;                                                          
}
else 
{
   N.cn=cn;
}
N.i=i;
H.Insert(N);   
              
}               
int MinCover(int **a,int v[],int n)
{
VC Y;
Y.w=new int[n+1];
for(int j=1;j<=n;j++)
{
   Y.w[j]=v[j];       //初始化VC類對象Y;
}
Y.a=a; 
Y.n=n;
Y.bestx=v;        //將地址賦予bestx,
Y.BBVC();
return Y.bestn;      //bestn是最後的最小頂點覆蓋集權重;
}                  
int main()
{
int u,v;
int n,c;
ifstream infile("input.txt");
if(!infile)
{
   cout<<"Can't open input.txt"<<endl;
   return 0;
}
ofstream outfile("output.txt");
if(!outfile)
{
   cout<<"Can't open output.txt"<<endl;
   return 0;
}
infile>>n>>c;
//Make2DArray(a,n+1,n+1);
int **a;
a=new int *[n+1];
for(int k=0;k<=n;k++)
   a[k]=new int[n+1];
for(int i=0;i<=n;i++)
   for(int j=0;j<=n;j++)
    a[i][i]=0;
p=new int[n+1];
for(i=1;i<=n;i++)
   infile>>p[i];
for(i=1;i<=c;i++)
{
   infile>>u>>v;
   a[u][v]=1;
   a[v][u]=1;
}
cout<<MinCover(a,p,n)<<endl;
for(i=1;i<=n;i++)
   cout<<p[i]<<" ";
cout<<endl;
return 0;
}
'input.txt'
7 7
1 100 1 1 1 100 10
1 6
2 4
2 5
3 6
4 5 
4 6
6 7
說明:在文章中,頂點與結點是兩個不同的概念,結點中有記錄當前加入頂點覆蓋集的 i,有加入頂點覆蓋集中的x[],有加入與頂點覆蓋集鄰接的c[]頂點集;
此程序的運行流程:首先是初始建最小堆過程,把每個頂點插入到堆中,在每個頂點的內部,X[]數組就是記錄此時的頂點覆蓋集,然後選取此結點內部頂點覆蓋集權重之和cn最小的頂點做爲擴展結點,然後以比此頂點標號大1的結點爲參考(i = E.i + 1),分別插入兩個結點到堆中,一個是 i 頂點加入頂點覆蓋集後的結點,一個是 i頂點沒有加入頂點覆蓋集後的結點,然後重新建堆,再重新移出堆結點,重複如此,直到所有頂點都被標記進x[]或c[]中()。

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章