ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

旅行商问题的动态规划解法

2021-08-14 18:01:42  阅读:224  来源: 互联网

标签:tsp 旅行 结点 kx 解法 数组 集合 动态 dp


解决思路:

        假设当前为一个规模为n且开始结点为0号结点的旅行商问题,那么,我们所要解决的问题可以转化为将0与{0,1,2,3…n}的有向(与集合中的顺序不一定一致)序列与0相连的最小值。假设这个最小值为k与0相连的情况下产生的,那么,我们又可以将问题分解为{0,1,2,…k-1,k+1,…n}的最优与k相连解加上k与0相连的距离耗费……综上所述,该问题可以划分成最优子问题的形式,故存在动态规划解法。

       基于以上分析思考,我们可以将集合用二进制数来表示,其中每一个二进制位标识一个结点,为1则表示该结点已在集合中,为0则表示该位不在集合中。将0号结点首先内置在每一个集合中。我们构造一个n*(2^(n-1))的矩阵作为dp数组,通过对该数组的填写完成对本问题最优解的寻找。

       依据以上的分析,我们可以得到该解法的dp矩阵填写方式如下:

        1.当集合中仅有一个元素时,初始化该列的第0行元素为该点到0号节点的距离。其余位置,若无效则填0,若有效则仅可将i号结点与j对应的节点(假定为k)相连,然后将k与0号结点相连。

        2.普通位置的结点,遍历j中对应集合含有的元素,假定为kx,若存在kx==i,则证明i已在集合中,该位置无效,填0。若不存在kx==i,则遍历kx,求d=a[i][kx] +dp[k][1<<(kx-1)^j]中的最小值,填到dp数组对应位置。

程序代码:

#include <iostream>
#include <string.h>
using namespace std;

int **a,**dp, n, m, bestc;
int tsp()
{
    int k, t, mind, d, kl, flag;
    if(n<=1) return 0;
//当集合中仅有一个元素时,初始化该列的第0行元素为该点到0号节点的距离
    for(int j=1, i=1; i<n; i++,j<<=1)
        dp[0][j]=a[0][i];    
    for(int j=1; j<m; j++)
    {
        for(int i=0; i<n; i++)
        {
            if(i==0)
            {
                //已经初始化的位置,无需再次填写
                if(dp[i][j]!=0)
                {
                    flag=1;
                    continue;
                }

            }
            k=0; t=j; mind=0x7f7f7f7f;
      //当集合中仅有一个元素时,初始化该列未初始化的位置,若无效则填0,
      //若有效则仅可将i号结点与j对应的节点(假定为k)相连,然后将k与//0号结点相连。
            if(flag==1)
            {
                while( !(t&1) )
                {k++;t=t>>1;} k++;
                if(i==k) dp[i][j]=0;
                else dp[i][j]=dp[0][j]+a[i][k];
                continue;
            }
 //普通位置的结点,遍历j中对应集合含有的元素,假定为kx,
//若存在kx==i,则证明i已在集合中,该位置无效,填0。
//若不存在kx==i,则遍历kx,求d=a[i][kx]+dp[k][1<<(kx-1)^j]中的最小值,填到dp数组对应位置
            while(t)
            {
                k++;
                if(k==1) kl=1;
                else kl=kl<<1;
                if(t&1)
                {
                    if(k==i)
                    {
                        mind=0;
                        break;
                    }
                    d=a[i][k]+dp[k][kl^j];
                    if(d<mind) mind=d;
                }
                t=t>>1;
            }
            dp[i][j]=mind;
        }
        flag=0;
    }
    return dp[0][m-1];
}

int main()
{
    cin>>n;
    m=1<<(n-1);
    a=new int *[n];
    dp=new int *[n];
    for(int i=0; i<=n; i++)
    {
        a[i]=new int [n];
        dp[i]=new int [m];
        memset(dp[i],0,m*sizeof(int));
    }
    for(int i=0; i<n; i++)
    {
        a[i][i]=0;
        for(int j=i+1; j<n; j++)
        {
            cin>>a[i][j];
            a[j][i]=a[i][j];
        }
    }
    //调用函数进行dp矩阵的填写
    bestc=tsp();
    cout<<bestc<<endl;

    return 0;
}

时间复杂度分析:

        该算法的主题部分在于函数tsp(),在此前的准备工作中,邻接矩阵的读入费时为 。在tsp()函数中,首先执行dp数组的初始化,填写j标识单个元素(除0位置元素外)存在于数组中的列的首行元素,该过程的时间复杂度为O(n),接下来进行两层for循环,对dp数组的每一个位置进行填写。其中,根据我们之前的算法设计过程可知,dp数组的大小为n行2^(n-1)列。在填写数据的过程中,需要对j进行不断地右移取数操作,来进行将i号点加入该集合的最小距离花费,因此该过程的时间复杂度为 。填完dp数组,tsp的功能就完成了。综合以上分析,动态规划法解决本实验问题的时间复杂度为

 

标签:tsp,旅行,结点,kx,解法,数组,集合,动态,dp
来源: https://blog.csdn.net/qq_45720855/article/details/119704151

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有