双调欧几里得旅行商问题 hdu 2224 |hdu 4824 [动态规划]

转自这里!!!!!!!!!!
欧几里得旅行商问题是对平面上给定的n个点确定一条连接各点的最短闭合旅程的问题。图a给出了7个点问题的解,这个问题的一般形式是NP完全的,故其解需要多于多项式的时间。

  J.K.Bentley建议通过只考虑双调旅程来简化问题,这种旅程即为从最左点开始,严格从左到最右点,再严格地从最右点回到最左点。图b显示了同样的7个点的问题的最短双调路线,在这种情况下,多项式的时间的算法是有可能的。

  描述一个确定最优双调路线的O(n^2)时间的算法。可以假设任何两点的x坐标都不相同。

解法:

  读了很多遍这个题,也看了网上好几篇关于这个问题的博客,有很多一部分是错误的却没有更正,于是自己实践整理了一份这个问题的解法。首先最大的疑惑在于理解什么叫做双调(Bitonic),读了很多解释的词条大概了解了双调的用处,我所理解的双调在这道题之中的思路就是将整个闭合的路线一个点展开,因为题中要求的是从左端向右端扫描,再从右端扫描回来。那么不妨将最左端的点作为出发点开始进行计算(从右端完全一致,不再赘述)。

  我们需要一个辅助的矩阵a[iLen+1][iLen+1],和所有动态规划问题一样矩阵的大小都是问题的规模+1,整个的计算过程是从左端到右端,也就是我们计算的最短路经从左端向右端生长的过程,辅助矩阵a[i][j]指的是p[i]到p[1]和p[1]到p[i-1]“共通”的最短路径,计算过程只利用矩阵的下三角部分,所以使前一个索引小与后一个索引。首先,将iLen个点存储到一个结构体/类数组之中,用来存放所有的点的坐标,记作数组p,p1,p2之间的距离记作dist(p1,p2)。

核心思想:

1)(前提)当我们计算第i个点或者将它并入最短路径的时候,前1.2.3…i-1个点已经形成了一条最短路径。

2)若要计算a[i][j],新加入的点p[j]的选择分支有三种,也就是路线规划“生长”情况有且只有三种:

  (一)当j-1〉i时,根据第(1)条我们需要做的就是在辅助矩阵中已经形成的子最短路径加上新增的边(按定义必然是先添加在更长的那半部分路线)

     就有 a[i][j]=a[i][j-1]+dist(j-1,j);

  (二)当j-1=i时,就是一次总结前面的子最短路径生成更长的新子最短路径的时候。

     表示为 a[i][j]=min{(a[k][j-1]+dist(k,j)) , (a[k-1][j-1])+dist(k-1,j)….}k为遍历值

  (三)当j=i 时,将整个图形封闭起来需要最后的两条边,实质上是(二)过程的一个分支

     即 a[i][j]=min{(a[k][j-1]+dist(k,j)+dist(j-1.j))…..}/k为遍历值

#include<iostream>
#include<vector>
#include<cstdlib>
#include<cmath>

#define MAX_VALUE 99999

class Point{
public:
    Point(double px=0,double py=0)
        :x(px),y(py){}//////
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值