以POJ3311为例

题目描述:

The Pizazz Pizzeria prides itself in delivering pizzas to its customers as fast as possible.
Unfortunately, due to cutbacks, they can afford to hire only one driver to do the deliveries. He will wait
for 1 or more (up to 10) orders to be processed before he starts any deliveries. Needless to say, he
would like to take the shortest route in delivering these goodies and returning to the pizzeria, even if it
means passing the same location(s) or the pizzeria more than once on the way. He has commissioned
you to write a program to help him.
输入:
3
0 1 10 10
1 0 1 2
10 1 0 10
10 2 10 0
0
输出:
8

此题使用一次floyd之后就变成了一道经典的TSP问题.那么下面将浅谈一下TSP问题

对于TSP问题:

指一个旅行商从一个城市触发,经过每一个城市一次且只有一次回到原来的地方,要求经过的距离最短.目前为止TSP问题是一个NP难题,目前并没有多项式时间以内的高效算法,使用动态规划来解决的话,复杂度为 n 2 2 n n^22^n n22n

对于旅行商问题,我们可以使用 d p [ s ] [ u ] dp[s][u] dp[s][u]来表示当前已走过的集合为 s s s并且从 u u u点出发走完所有剩余点并回到出发点的最小距离

那么对于一个点,我们要计算这个点到出发点的距离,显然可以由他的邻接点来进行递推.因为我们的这个点到达终点的路径显然是会经过他的邻接点的.并且这个邻接点的状态方程显然就加入了我们的 v v v这个状态.所以此时我们不难写出以下的转移方程:

d p [ { s } ] [ u ] = m i n ( d p [ { s } ] [ u ] , d p [ { s } ⋃ { v } ] [ v ] + m p [ u ] [ v ] ) dp[\{s\}][u]=min(dp[\{s\}][u],dp[\{s\}\bigcup\{v\}][v]+mp[u][v]) dp[{s}][u]=min(dp[{s}][u],dp[{s}⋃{v}][v]+mp[u][v])

其中mp[u][v]为邻接表中u,v两点直接的距离,为什么直接使用邻接表储存呢.因为TSP问题的复杂度极大,所以实际问题中的点的个数将不会很多,所以邻接表足以,且邻接表更方便使用

那么接下来的问题就是如何存储我们的状态了

对于这个问题,我们将使用状态压缩的一种方式来存储,对于每一种状态,我们都使用一串二进制数来存储,那么对于每一个点假设在我们的点集之中,那就意味着我们的对应的二进制位为1即可

( s > > v ) & 1 (s>>v)\&1 (s>>v)&1 表示从点集s中提取出我们的v点的状态
( s ∣ ( 1 < < v ) ) (s|(1<<v)) (s∣(1<<v)) 表示将我们的v点的状态加入到我们的点集s中

对于边界问题:

显然我们最终的状态将会是 d p [ ( 1 < < n ) − 1 ] [ 0 ] dp[(1<<n)-1][0] dp[(1<<n)−1][0]表示最终全部点都走过并且最终在0点

那么我们最终的答案就是 d p [ 0 ] [ 0 ] dp[0][0] dp[0][0]代表刚开始没有走过任何一个点并且从0开始的最短距离

对于我们的TSP问题,接下来我将分别展示递推和记搜两种求解方式

对于递推:

 dp[(1<<n)-1][0]=0;for(int s=(1<<n)-2;s>=0;s--) {for(int u=0;u<n;u++) {for(int v=0;v<n;v++) {if((!(s>>u&1)&&!(u==0&&s==0))||mp[u][v]==inf) continue;if(!(s>>v&1)) {dp[s][u]=min(dp[s][u],dp[s|(1<<v)][v]+mp[u][v]);}}}}

也就是枚举每一种状态,然后更新每一种状态中每一个节点的值

对于约束条件部分:

! ( s > > u & 1 ) !(s>>u\&1) !(s>>u&1)表示当前枚举的出发点不在我们的点集当中,那么显然我们此时不应该枚举我们的u节点,但是这个并不是一定的,因为当我们求解我们的dp[0][0]时,最终需要枚举的状态是s==0并且需要从u=0开始出发,所以当我们的s==0并且u==0时,我们需要继续进行递推


对于记忆化搜索,我们有以下代码(感觉记搜比较好理解):

int solve(int s,int u) {//s表示目前走过的点集,u表示目前所在的点的位置if(dp[s][u]>=0) return dp[s][u]; if(s==(1<<n)-1&&u==0) return dp[s][u]=0;if(s!=(1<<n)-1&&u==0&&s!=0) return dp[s][u]=inf;//对于此处剪枝,因为当我们并没有走完全部的点却提前到初始点显然是不合法的int ans=inf;for(int v=0;v<n;v++) {if(!(s>>v&1)&&mp[u][v]!=inf) {ans=min(ans,solve(s|(1<<v),v)+mp[u][v]);}}return dp[s][u]=ans;
}
solve(0,0);

update in 2022/12

博主在打题的过程中发现了一个更容易理解和实现的TSP递推解法.emmm,之前介绍的两种方法都是倒推的,这就在理解上有一点点的绕,所以接下来讲介绍一种顺推的方法(虽然这种方法在优化程度上并不如前两种方法,但是更为简便)

dp[1][0]=0;
for(int S=1;S<(1<<r);S++) {for(int u=0;u<r;u++) {if(!((S>>u)&1)) continue;for(int v=0;v<r;v++) {if((S>>v)&1) continue;dp[S|(1<<v)][v]=min(dp[S|(1<<v)][v],dp[S][u]+mp[u][v]);}}
}
int ans=inf;
for(int i=0;i<r;i++) {ans=min(ans,dp[(1<<n)-1][i]+mp[i][0]);
}

怎么说呢,这个方法就是将之前倒推的方法给正了过来,更符合一般人的脑回路??所以此方法的dp[S][u]方程的思想就是当你达到了S状态,并且此时站在u位置的最小费用.所以到达v位置(也就是u的邻接点),显然可以通过u节点更新而来,比之前的好理解多了.

但是在我们的dp方程中,我们求出的是走完所有节点并且到达最终的点的最小贡献,但是我们最终是需要回到源点的,所以此时加上我们的两点之间的距离(注意即使不通也没有关系,我们只要初始化 i n f inf inf即可)

浅谈旅行商问题(TSP问题)相关推荐

  1. 技术分享:浅谈滴滴派单算法

    浅谈滴滴派单算法 原创: 王犇 刘春阳 徐哲 滴滴技术 桔妹导读:说到滴滴的派单算法,大家可能感觉到既神秘又好奇,从出租车扬召到司机在滴滴平台抢单最后到平台派单,大家今天的出行体验已经发生了翻天覆地的 ...

  2. Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME

    Java开发的B/S程序生成并向客户端发送excel文件:浅谈MIME 1.定义 MIME(Multipurpose Internet Mail Extensions)多用途互联网邮件扩展类型.是设定 ...

  3. 计算机科学数学理论浅谈

    计算科学数学理论浅谈 以前,总是对于数学的学习嗤之以鼻,认为没有很大的实用性,这也是为何后来跨专业考研的一个重要动机,但是随着后续学习的深入,逐渐体 会到了数学在现实工作中的分量,而这种对思考的能力的 ...

  4. 浅谈MySQL存储引擎-InnoDBMyISAM

    浅谈MySQL存储引擎-InnoDB&MyISAM 存储引擎在MySQL的逻辑架构中位于第三层,负责MySQL中的数据的存储和提取.MySQL存储引擎有很多,不同的存储引擎保存数据和索引的方式 ...

  5. 【大话设计模式】——浅谈设计模式基础

    初学设计模式给我最大的感受是:人类真是伟大啊!单单是设计模式的基础课程就让我感受到了强烈的生活气息. 个人感觉<大话设计模式>这本书写的真好.让貌似非常晦涩难懂的设计模式变的生活化.趣味化 ...

  6. 学校计算机机房好处,浅谈学校计算机机房维护

    浅谈学校计算机机房维护    现在的学校机房都配置了数量较多的计算机,而且机房的使用非常频繁.对于怎样维护好计算机,特别是计算机软件系统,对广大计算机教师来说是一个很重要且非常现实的问题.下面就本人在 ...

  7. java 中的单元测试_浅谈Java 中的单元测试

    单元测试编写 Junit 单元测试框架 对于Java语言而言,其单元测试框架,有Junit和TestNG这两种, 下面是一个典型的JUnit测试类的结构 package com.example.dem ...

  8. mybatis与php,浅谈mybatis中的#和$的区别

    浅谈mybatis中的#和$的区别 发布于 2016-07-30 11:14:47 | 236 次阅读 | 评论: 0 | 来源: 网友投递 MyBatis 基于Java的持久层框架MyBatis 本 ...

  9. 浅谈GCC预编译头技术

    浅谈GCC预编译头技术 文/jorge --谨以此文,悼念我等待MinGW编译时逝去的那些时间. 其 实刚开始编程的时候,我是丝毫不重视编译速度之类的问题的,原因很简单,因为那时我用BASICA.后来 ...

最新文章

  1. pandas使用datetime创建示例dataframe:包含完整的时分秒信息、创建时间索引、使用不同的时间频率、date_range中参数freq的偏移量别名
  2. FireDAC 下的 Sqlite [4] - 创建数据库
  3. 《高性能JavaScript》第九章 构建并部署高性能JavaScript应用
  4. r java_如何在R中使用JAVA写的程序包?
  5. OO第三次博客作业——规格
  6. LB负载均衡集群--LVS
  7. Java包装类型对象比较相等性注意事项
  8. 摩拜回应裁员传闻:属正常业务调整 部分岗位仍在招聘
  9. 刻不容缓!联合国加开会议讨论「如何限制杀人机器人」
  10. 关于axios中'$router' of undefined问题
  11. Android--手势及触摸事件的注意点(一)
  12. JAVA怎么打开pkg_PKG文件在电脑上怎么打开!(普通PC)
  13. 【ERP知识】一个VMI(供应商管理库存)实现方案
  14. Android项目的targetSDK=23,在低于Android6.0的部分测试机(类似华为)上运行时出现的系统权限问题...
  15. iOS小技能:SKU视图搭建
  16. 新版标准日本语初级_第三十七课
  17. mysql numeric
  18. java web 登录_javaWeb实现登录功能
  19. 长春理工大学计算机考研资料汇总
  20. 我想给我的手机下载和弦铃声,哪里可以下?

热门文章

  1. 拉卡拉金融科技收入Q1暴涨557%!贷款引流占7成,流量变现能拯救支付吗?
  2. Javaweb中layui数据表格的实现
  3. 天能动力加码锂电池研发
  4. 爱奇艺APP全面适配iOS 14 首批支持画中画功能 追剧聊天两不误
  5. 高德地图规划路线,并显示该路线的坐标
  6. xmapp安装、配置及dreamweaver站点建立
  7. springboot 自定义切面类
  8. 我把全国旅游数据用Python爬下来后发现,这个地方才是真正的旅游胜地
  9. [原创] 神的计划3 - 创世纪–诺亚方舟
  10. Java中大文件读取,内存放不下怎么办?