TSP问题的解决方法

著名的货郎担架问题大家都明白,现在要求解它。有两种办法
方法一,暴力枚举法,举出所有的路径,这方法最简单,但是,需要N!的复杂度,当n比较大时,完全没有可计算性,当然,生成n!种排列比较简单,不需要什么高端的技巧。在此不解释这种解法

方法二,动态规划,设T(Vi,V)表示从V1经过V中所有结点到Vi的最短路径值,于是我们有以下的转移方程

        T(Vi,V)=min{D(k,i)+T(Vk,V\{Vk}}其中Vk是V中元素,其中D(k,i)表示第k个结点到第i个的距离(允许取无穷大)。我们要求解的问题是T(V1,V\{V1}).----即我们从V1出了,遍历V中除V1之外的结点,然后回到V1.根据这个原则,我们用二进制位表示每一个元素的取与不取。则知道代码如下:

 

  1. //author:sy1206321  
  2. #include <iostream>  
  3. using std::endl;  
  4. using std::cin;  
  5. using std::cout;  
  6.   
  7. unsigned    int     iNodeCount;//结点的个数  
  8. unsigned    int**   lpDpArray;//动态规划时的数组  
  9. unsigned    int**   lpGraph;//存储图的数据  
  10. bool        **      bHasCaculate;//存储一条路径是否访问过  
  11. unsigned    int**   lpPath;//存储最短的路径  
  12.   
  13. bool    FreeResource();//free memory  
  14. bool    InitData();//init graph data  
  15. void    Search();//搜索最短的路径  
  16. unsigned    int GetMinPath(unsigned int iNode, unsigned int iNodeSet);  
  17. void    ShowPath();//显示其中一个路径  
  18.   
  19. int main(){  
  20.     InitData();  
  21.     Search();  
  22.     cout<<lpDpArray[1][(1<<iNodeCount)-2]<<endl;  
  23.     ShowPath();  
  24.     FreeResource();  
  25.     system("PAUSE");  
  26. }  
  27.   
  28. bool    FreeResource(){//free memory  
  29.     for(int iIndex= 0; iIndex<= iNodeCount; ++iIndex){  
  30.         delete[]    lpDpArray[iIndex];  
  31.         delete[]    bHasCaculate[iIndex];  
  32.         delete[]    lpGraph[iIndex];  
  33.         delete[]    lpPath[iIndex];  
  34.     }  
  35.     delete[]    lpDpArray;  
  36.     delete[]    bHasCaculate;  
  37.     delete[]    lpGraph;  
  38.     delete[]    lpPath;  
  39.     return  true;  
  40. }  
  41.   
  42. bool    InitData(){//allocate memory and init data  
  43.     cout<<"请输入结点个数:"<<endl;  
  44.     cin>>iNodeCount;  
  45.     lpDpArray       =   new unsigned int*[iNodeCount+ 1];  
  46.     lpDpArray[0]    =   NULL;  
  47.     bHasCaculate    =   new bool*[iNodeCount+ 1];  
  48.     bHasCaculate[0]=    NULL;  
  49.     lpGraph         =   new unsigned int*[iNodeCount+ 1];  
  50.     lpGraph[0]      =   NULL;  
  51.     lpPath          =   new unsigned int*[iNodeCount+ 1];  
  52.     lpPath[0]       =   NULL;  
  53.     for(int iIndex= 1; iIndex<= iNodeCount; ++iIndex){  
  54.         lpDpArray[iIndex]       =   new unsigned int[1<<iNodeCount];  
  55.         bHasCaculate[iIndex]    =   new bool[1<<iNodeCount];  
  56.         lpGraph[iIndex]     =   new unsigned int[iNodeCount+1];  
  57.         lpPath[iIndex]          =   new unsigned int[1<<iNodeCount];  
  58.     }  
  59.     cout<<"请输入图的数据,如果不存在就输入0"<<endl;  
  60.     //读入图的数据,不存在则用无穷表示(static_cast<int>(-1))  
  61.     for(unsigned int iRow= 1; iRow<= iNodeCount; ++iRow){  
  62.         for(unsigned int iCol= 1; iCol<= iNodeCount; ++iCol){  
  63.             cin>>lpGraph[iRow][iCol];  
  64.             if(!lpGraph[iRow][iCol]){  
  65.                 lpGraph[iRow][iCol] =   static_cast<unsigned int>(-1);  
  66.             }  
  67.         }  
  68.     }  
  69.     //把bHasCaculate, lpDpArray, lpPath数组全部清零  
  70.     for(unsigned int iRow=1; iRow<= iNodeCount; ++iRow){  
  71.         for(unsigned int iCol= 1; iCol< (1<<iNodeCount); ++iCol){  
  72.             bHasCaculate[iRow][iCol]    =   false;  
  73.             lpDpArray[iRow][iCol]       =   static_cast<unsigned int>(-1);  
  74.             lpPath  [iRow][iCol]        =   0;  
  75.         }  
  76.     }  
  77.   
  78.     return  true;  
  79. }  
  80.   
  81. //=========================================================================  
  82. //lpDpArray[iNode][iNodeSet]表示从Node(1)到Node(iNode)经过iNodeSet集合中的点的  
  83. //最小值  
  84. //=========================================================================  
  85. void    Search(){  
  86.     //显然当iNodeSet为0是,表示空集  
  87.     for(int iNode= 1; iNode<= iNodeCount; ++iNode){  
  88.         lpDpArray[iNode][0]     =   lpGraph[1][iNode];  
  89.         lpPath    [iNode][0]    =   1;  
  90.         bHasCaculate[iNode][0]  =   true;  
  91.     }  
  92.     lpDpArray[1][(1<<iNodeCount)-2]   =   GetMinPath(1, (1<<iNodeCount)-2);  
  93. }  
  94.   
  95. unsigned    int GetMinPath(unsigned int iNode, unsigned int iNodeSet){  
  96.     if(bHasCaculate[iNode][iNodeSet]){  
  97.         return  lpDpArray[iNode][iNodeSet];  
  98.     }  
  99.     unsigned int iMinValue  =   static_cast<int>(-1);  
  100.     for(int iPreNode= 1; iPreNode<= iNodeCount; ++iPreNode){  
  101.         if(((1<<(iPreNode-1)) & iNodeSet) && (lpGraph[iPreNode][iNode]!= -1)){//iPreNode is a elem of iNodeSet  
  102.             unsigned int iPreValue  =   GetMinPath(iPreNode, iNodeSet&(~(1<<(iPreNode-1))));  
  103.             if((iPreValue!= -1) && iPreValue+ lpGraph[iPreNode][iNode]< iMinValue){//update value  
  104.                 lpPath[iNode][iNodeSet]     =   iPreNode;  
  105.                 iMinValue   =   iPreValue+ lpGraph[iPreNode][iNode];  
  106.             }  
  107.         }  
  108.     }  
  109.     lpDpArray[iNode][iNodeSet]  =   iMinValue;  
  110.     bHasCaculate[iNode][iNodeSet]       =   true;  
  111.     return  lpDpArray[iNode][iNodeSet];  
  112. }  
  113.   
  114. void    ShowPath(){  
  115.     int *   path=   new int[iNodeCount+ 1];  
  116.     int ivalue= (1<<iNodeCount)-1;  
  117.     int iPreNode    =   1;  
  118.     int iNodeIndex  =   0;  
  119.     while(ivalue){  
  120.         ivalue-=    (1<<(iPreNode-1));  
  121.         path[iNodeCount-iNodeIndex] =   iPreNode;  
  122.         ++iNodeIndex;  
  123.         iPreNode    =   lpPath[iPreNode][ivalue];  
  124.     }  
  125.     path[0]=    1;  
  126.     for(iNodeIndex= 0; iNodeIndex<= iNodeCount; ++iNodeIndex){  
  127.         cout<<path[iNodeIndex]<<(iNodeIndex== iNodeCount ? "\n":"->");  
  128.     }  
  129.     delete[]    path;  
  130. }  

        在其中我们并没有完全采用动态规划,而是采用它的一个变种---备忘录,我们把已经求得的还会重新利用的小的结果记录起来,下次再求解这个小问题的时候直接查表就可以了,而不是像动态规划那样,在求解一个大问题的时候要求所有的小问题都已经被解决。

 

易求算法时间复杂度是O(n*2^n)空间也是,显然在时间上比n!要快许多,而对于n!我们由斯特林公式知n!=(n/e)^n*(2*pi*n)^0.5,显然比2^n*n要大许多的

 

其中我给的一组输入值是:

6(6个顶点)

0  10 20 30 40 50 
12 0  18 30 25 21
23 19 0  5  10 15
34 32 4  0  8  16
45 27 11 10 0  18
56 22 16 20 12 0

以上的是边的权值(有向图

posted @ 2012-12-26 12:40  夜月神  阅读(1275)  评论(0编辑  收藏  举报