动态规划解决TSP问题(C++)

问题:
TSP问题是指旅行家要旅行n个城市,要求各个城市经历且仅经历一次,然后回到出发城市,并要求所走路程最短。

解决思路:
以四个城市为例讲解
在这里插入图片描述
假设n个顶点用0~ n-1个数字编号,首先要生成1~ n-1个元素的子集存放在数组sub[] 中, 设数组d[n][2^n-1]存放迭代结果,其中d[ i ][ j ]表示从顶点 i 经过子集sub[]中顶点一次且仅一次,最后回到出发点0的最短路径长度。

城市个数为4,因此,结果矩阵的列数为2^(4-1)=8 。

用二进制表示子集
例如:第6列,标号为5,用二进制表示为101。三位由高到低分别代表元素3,2,1 。该位为1表示该元素在子集中存在,为0表示不存在。所以101表示子集{1,3}。

**正常人类手写填写顺序
在这里插入图片描述

**程序输出结果顺序
在这里插入图片描述

函数功能简介:

int c[20][20];//城市间距
int d[20][100];//TSP最终结果
int col;//TSP最终结果表的列数
int sub[100];//子集
void setDistance(int num);//创建城市间间距矩阵C
int subContain(int n);//判断元素是否存在于子集
int subGather(int n,int num);
/*
	例:将5(二进制101),转化为子集形式
	{1,3}存放在集合sub[]中,
	并返回集合元素个数length;
*/
int deSub(int k,int j);
/*
	例:求集合{1,3}剔除元素3后的子集.
	{1,3}用二进制101表示,剔除元素3
	相当于将右数第三位置0.
	因此,可以将数字1(二进制001),左移2位为100
	再做差101-100=001
	得到子集{1};
*/
int doTSP(int num);
void showResult(int num);//输出结果

完整代码:

#include <iostream>

using namespace std;
int c[20][20];//城市间距
int d[20][100];//TSP表结果
int col;//TSP表的列数
int sub[100];//子集
//求子集,详细解释见上面
int subGather(int n,int num)
{
    int i,length;
    length=0;
    for(i=1;i<num;i++)
    {
        if(n&1==1)
            sub[length++]=i;
        n=n>>1;
    }
    sub[length]=-1;
    return length;
}
//检查元素是否存在于该子集
int subContain(int n)
{
    int i=0;
    while(sub[i]!=-1)
    {
        if(sub[i]==n) return 1;
        i++;
    }
    return 0;
}
//创建城市间距矩阵
void setDistance(int num)
{
    int i,j;
    cout<<"Set distance:\n";
    for(i=0;i<num;i++)
    {
        for(j=0;j<num;j++)
        {
            if(i==j)
                c[i][j]=-1;
            else
            {
                cout<<"Input the distance between City"<<i<<" and City"<<j<<":";
                cin>>c[i][j];
            }
        }
    }
    cout << "Set completely!" << endl;
}
//详细解释见上面
int deSub(int k,int j)
{
    int temp=1;
    temp=temp<<(k-1);
    return j-temp;
}
//TSP
int doTSP(int num)
{
    int i,j;
    //计算矩阵d[][]的列数
    for(i=0,col=1;i<num-1;i++,col*=2);
    //初始化矩阵d[][]第一列
    for(i=1;i<num;i++)
        d[i][0]=c[i][0];
    //填写第2到col-1列内容
    int length;
    int aaa=1;
    while(aaa<num-1)//按照子集元素个数递增的顺序填表
    {
        for(j=1;j<col;j++)
        {
            length=subGather(j,num);
            if(length==aaa)
            {
                for(i=1;i<num;i++)
                {
                    if(subContain(i)==0)//元素不存在于子集
                    {
                        int md=10000;//最小值
                        int temp;
                        int k;
                        for(k=0;k<length;k++)
                        {
                            temp=c[i][sub[k]]+d[sub[k]][deSub(sub[k],j)];
                            if(temp<md)
                                md=temp;
                        }
                        d[i][j]=md;
                    }
                }
            }
        }
        aaa++;
    }
    //填写最后一列
    int md=10000;//最小值
    int temp;
    int k;
    length=subGather(col-1,num);
    for(k=0;k<length;k++)
    {
        temp=c[0][sub[k]]+d[sub[k]][deSub(sub[k],col-1)];
        if(temp<md)
            md=temp;
    }
    d[0][col-1]=md;
    return d[0][col-1];
}
//输出结果
void showResult(int num)
{
    int i,j;
    for(i=0;i<num;i++)
    {
        for(j=0;j<col;j++)
            cout<<d[i][j]<<"\t";
        cout<<endl;
    }
}
int main()
{
    int num;//城市个数
    int p_length;//最短路径长度
    cout<<"Input the number of cities:";
    cin>>num;
    setDistance(num);
    p_length=doTSP(num);
    cout<<"The length of the shortest path is "<<p_length<<endl;
    cout<<"TSP table:\n";
    showResult(num);
    return 0;
}

运行结果:
在这里插入图片描述

致谢~
在这里插入图片描述

  • 17
    点赞
  • 66
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值