动态规划 解TSP旅行商问题

2024-05-14 16:58
文章标签 动态 规划 问题 tsp 旅行

本文主要是介绍动态规划 解TSP旅行商问题,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

原文地址: http://blog.csdn.net/gfaiswl/article/details/4749713

1.问题定义

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

      假设现在有四个城市,0,1,2,3,他们之间的代价如图一,可以存成二维表的形式

              image        image

                      图一                                                                                               

        现在要从城市0出发,最后又回到0,期间1,2,3都必须并且只能经过一次,使代价最小。

2.动态规划可行性

        设s, s1, s2, …, sp, s是从s出发的一条路径长度最短的简单回路,假设从s到下一个城市s1已经求出,则问题转化为求从s1到s的最短路径,显然s1, s2, …, sp, s一定构成一条从s1到s的最短路径,所以TSP问题是构成最优子结构性质的,用动态规划来求解也是合理的。

3.推导动态规划方程

        假设从顶点s出发,令d(i, V’)表示从顶点i出发经过V’(是一个点的集合)中各个顶点一次且仅一次,最后回到出发点s的最短路径长度。

        推导:(分情况来讨论)

        ①当V’为空集,那么d(i, V’),表示从i不经过任何点就回到s了,如上图的 城市3->城市0(0为起点城市)。此时d(i, V’)=Cis(就是 城市i 到 城市s 的距离)、

        ②如果V’不为空,那么就是对子问题的最优求解。你必须在V’这个城市集合中,尝试每一个,并求出最优解。

           d(i, V’)=min{Cik +  d(k, V’-{k})}

           注:Cik表示你选择的城市和城市i的距离,d(k, V’-{k})是一个子问题。

        综上所述,TSP问题的动态规划方程就出来了:

         image

4.实例分析

     现在对问题定义中的例子来说明TSP的求解过程。(假设出发城市是 0城市)

     image

    ①我们要求的最终结果是d(0,{1,2,3}),它表示,从城市0开始,经过{1,2,3}之中的城市并且只有一次,求出最短路径.

    ②d(0,{1,2,3})是不能一下子求出来的,那么他的值是怎么得出的呢?看上图的第二层,第二层表明了d(0,{1,2,3})所需依赖的值。那么得出:

       d(0,{1,2,3})=min  {

                                    C01+d(1,{2,3})

                                    C02+d{2,{1,3}}

                                    C03+d{3,{1,2}}

                                  }

     ③d(1,{2,3}),d(2,{1,3}),d(3,{1,2})同样也不是一步就能求出来的,它们的解一样需要有依赖,就比如说d(1,{2,3})

       d(1,{2,3})=min{

                              C12+d(2,{3})                             

                              C13+d(3,{2})

                              }

       d(2,{1,3}),d(3,{1,2})同样需要这么求。

    ④按照上面的思路,只有最后一层的,当当V’为空集时,Cis的值才可以求,它的值是直接从

image

这张表里求得的。

     5.编程思路

        将d(i, V’)转换成二维表,d[i][j]

image

        在程序中模拟填表的过程,主要要考虑到j这个参数的表示,它要代表一个集合,可以用二维数组来表示。

   6.源代码

注:由于本人水平有限,并且主要在这里是体现思路,所以程序并不是很完善,代码质量也不高,很地方可以写得通用一些,所以这里只是提供一个参考,程序的进一步完善,由读者自由发挥。

#include 
#include

int IsIncluded(int x,int array[3])//x是否包含在数组中 

    if((array[0] != x) && (array[1] != x) && (array[2] != x)) 
        return 0; 
    return 1; 

int Left(int k,int array[3],int V[8][3])//实现V'-{k} 的下标检索 

    int i = 0,index = 0,array_0_count = 0,array_1_count = 0,array_2_count = 0,array_3_count = 0; 
    int V_0_count = 0,V_1_count = 0,V_2_count = 0,V_3_count = 0; 
    int temp[3]; 
    for(i = 0; i < 3; i++) 
        temp[i] = array[i]; 
    for(i = 0; i < 3; i++) 
        if(temp[i] == k) 
            temp[i] = 0;  //相当于去掉k这个城市 
    for(i = 0; i < 3; i++) 
    { 
        if(temp[i] == 0) 
            array_0_count++; 
        else if(temp[i] == 1) 
            array_1_count++; 
        else if(temp[i] == 2) 
            array_2_count++; 
        else 
            array_3_count++; 
    } 
    for(index = 0; index < 8; index++) 
    { 
        for(i=0; i < 3; i++) 
        { 
            if(V[index][i] == 0) 
                V_0_count++; 
            else if(V[index][i] == 1) 
                V_1_count++; 
            else if(V[index][i] == 2) 
                V_2_count++; 
            else 
                V_3_count++; 
        } 
        if((array_0_count == V_0_count) && (array_1_count == V_1_count) 
            && (array_2_count == V_2_count) && (array_3_count == V_3_count)) 
            return index; 
        V_0_count = 0; 
        V_1_count = 0; 
        V_2_count = 0; 
        V_3_count = 0; 
    } 
    return 0; 
}

void TSP(int d[4][8],int c[4][4],int V[8][3],int n) 

    int i = 0,j = 0,k = 0;

    for(i = 1; i < n; i++)//V'为空时,给赋值, 
        d[i][0] = c[i][0];

    for(j = 1; j < 7; j++)//按列遍历不同集合,{1},{2},{3},{1,2},{1,3}..... 
    { 
        for(i = 1; i < n; i++)//遍历城市1,2,3 
        { 
            if( !IsIncluded(i,V[j]) )//i必须不在集合中,否则就属于经过两次,不符合题意 
            { 
                for(k = 0; k < 3; k++)//分别试探集合中的每一点,取最小值 
                { 
                    if((V[j][k] != 0) && ((c[i][V[j][k]] + d[V[j][k]][Left(V[j][k],V[j],V)]) < d[i][j])) 
                        d[i][j] = c[i][V[j][k]] + d[V[j][k]][Left(V[j][k],V[j],V)]; 
                } 
            } 
        }//end of     for(i = 1; i < n; i++)//遍历城市1,2,3 
    }//end of for(j = 1; j < ((int)pow(2,n)-1); j++) 
    for(k = 0; k < 3; k++)//分别试探下一步为集合中的任何一点,取最小值 
    { 
        if((V[7][k] != 0) && (c[0][V[7][k]] + d[V[7][k]][Left(V[7][k],V[7],V)]) < d[0][7]) 
            d[0][7] = c[0][V[7][k]] + d[V[7][k]][Left(V[7][k],V[7],V)]; 
    } 

void main() 

    int V[8][3]= 
    { 
        0,0,0, 
        0,0,1, 
        0,0,2, 
        0,0,3, 
        0,1,2, 
        0,1,3, 
        0,2,3, 
        1,2,3 
    }; 
    int c[4][4]= 
    { 
        0,3,6,7, 
        5,0,2,3, 
        6,4,0,2, 
        3,7,5,0 
    }; 
    int d[4][8]={0},i=0,j=0;

    for(i=0; i<4; i++) 
        for(j=0; j<8; j++) 
            d[i][j]=1000;   //假设1000为无穷大 
    TSP(d,c,V,4); 
    printf("The least road is:%d/n",d[0][7]); 
}

这篇关于动态规划 解TSP旅行商问题的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/989313

相关文章

好题——hdu2522(小数问题:求1/n的第一个循环节)

好喜欢这题,第一次做小数问题,一开始真心没思路,然后参考了网上的一些资料。 知识点***********************************无限不循环小数即无理数,不能写作两整数之比*****************************(一开始没想到,小学没学好) 此题1/n肯定是一个有限循环小数,了解这些后就能做此题了。 按照除法的机制,用一个函数表示出来就可以了,代码如下

hdu1043(八数码问题,广搜 + hash(实现状态压缩) )

利用康拓展开将一个排列映射成一个自然数,然后就变成了普通的广搜题。 #include<iostream>#include<algorithm>#include<string>#include<stack>#include<queue>#include<map>#include<stdio.h>#include<stdlib.h>#include<ctype.h>#inclu

第10章 中断和动态时钟显示

第10章 中断和动态时钟显示 从本章开始,按照书籍的划分,第10章开始就进入保护模式(Protected Mode)部分了,感觉从这里开始难度突然就增加了。 书中介绍了为什么有中断(Interrupt)的设计,中断的几种方式:外部硬件中断、内部中断和软中断。通过中断做了一个会走的时钟和屏幕上输入字符的程序。 我自己理解中断的一些作用: 为了更好的利用处理器的性能。协同快速和慢速设备一起工作

动态规划---打家劫舍

题目: 你是一个专业的小偷,计划偷窃沿街的房屋。每间房内都藏有一定的现金,影响你偷窃的唯一制约因素就是相邻的房屋装有相互连通的防盗系统,如果两间相邻的房屋在同一晚上被小偷闯入,系统会自动报警。 给定一个代表每个房屋存放金额的非负整数数组,计算你 不触动警报装置的情况下 ,一夜之内能够偷窃到的最高金额。 思路: 动态规划五部曲: 1.确定dp数组及含义 dp数组是一维数组,dp[i]代表

购买磨轮平衡机时应该注意什么问题和技巧

在购买磨轮平衡机时,您应该注意以下几个关键点: 平衡精度 平衡精度是衡量平衡机性能的核心指标,直接影响到不平衡量的检测与校准的准确性,从而决定磨轮的振动和噪声水平。高精度的平衡机能显著减少振动和噪声,提高磨削加工的精度。 转速范围 宽广的转速范围意味着平衡机能够处理更多种类的磨轮,适应不同的工作条件和规格要求。 振动监测能力 振动监测能力是评估平衡机性能的重要因素。通过传感器实时监

缓存雪崩问题

缓存雪崩是缓存中大量key失效后当高并发到来时导致大量请求到数据库,瞬间耗尽数据库资源,导致数据库无法使用。 解决方案: 1、使用锁进行控制 2、对同一类型信息的key设置不同的过期时间 3、缓存预热 1. 什么是缓存雪崩 缓存雪崩是指在短时间内,大量缓存数据同时失效,导致所有请求直接涌向数据库,瞬间增加数据库的负载压力,可能导致数据库性能下降甚至崩溃。这种情况往往发生在缓存中大量 k

软考系统规划与管理师考试证书含金量高吗?

2024年软考系统规划与管理师考试报名时间节点: 报名时间:2024年上半年软考将于3月中旬陆续开始报名 考试时间:上半年5月25日到28日,下半年11月9日到12日 分数线:所有科目成绩均须达到45分以上(包括45分)方可通过考试 成绩查询:可在“中国计算机技术职业资格网”上查询软考成绩 出成绩时间:预计在11月左右 证书领取时间:一般在考试成绩公布后3~4个月,各地领取时间有所不同

6.1.数据结构-c/c++堆详解下篇(堆排序,TopK问题)

上篇:6.1.数据结构-c/c++模拟实现堆上篇(向下,上调整算法,建堆,增删数据)-CSDN博客 本章重点 1.使用堆来完成堆排序 2.使用堆解决TopK问题 目录 一.堆排序 1.1 思路 1.2 代码 1.3 简单测试 二.TopK问题 2.1 思路(求最小): 2.2 C语言代码(手写堆) 2.3 C++代码(使用优先级队列 priority_queue)

poj 2976 分数规划二分贪心(部分对总体的贡献度) poj 3111

poj 2976: 题意: 在n场考试中,每场考试共有b题,答对的题目有a题。 允许去掉k场考试,求能达到的最高正确率是多少。 解析: 假设已知准确率为x,则每场考试对于准确率的贡献值为: a - b * x,将贡献值大的排序排在前面舍弃掉后k个。 然后二分x就行了。 代码: #include <iostream>#include <cstdio>#incl

代码随想录冲冲冲 Day39 动态规划Part7

198. 打家劫舍 dp数组的意义是在第i位的时候偷的最大钱数是多少 如果nums的size为0 总价值当然就是0 如果nums的size为1 总价值是nums[0] 遍历顺序就是从小到大遍历 之后是递推公式 对于dp[i]的最大价值来说有两种可能 1.偷第i个 那么最大价值就是dp[i-2]+nums[i] 2.不偷第i个 那么价值就是dp[i-1] 之后取这两个的最大值就是d