广义旅行商问题

本文介绍了广义旅行商问题的定义,通过实例解释了如何使用Dijkstra算法寻找最短路径,并探讨了算法的时间复杂度。在Dijkstra算法的基础上,文章进一步运用动态规划求解最优解,分析了动态规划的时间复杂度和存储需求。通过对算法的优化,成功提高了求解效率,为解决大规模问题奠定了基础。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

问题描述

广义旅行商问题:给定一个加权图G=(V, E,W),其中图中的边上有权值(所有权值为正)。给定一个源顶点s,和一个目标顶点点t,以及一个包含k个顶点的查询集合Q={vi1,vi2,…,vik},其中k<=5。要求设计一个动态规划算法计算从s到t并且经过集合Q中所有顶点的最短路径。

要求:
1. 利用自己熟悉的编程语言实现算法,并且从以下URL中下载图数据进行测试
http://snap.stanford.edu/data/roadNet-CA.html其中边的权值可以随机生成一个正数即可。
测试时,可以随机生成顶点s,t,和集合Q (集合Q中的元素可以随机生成3至5个顶点),要求计算最短路径长度以及输出最短路径,同时统计算法的时间消耗和空间消耗。K值越大,成绩越高


介绍

这道题目是本人在大三《算法设计与分析》期末大作业的选题~

个人在做这个算法大作业的时候呢,哎,好多坑要爬 QAQ,所以呢想和大家分享一下,我在做这个题目的时候的流程&想法

存在较大瑕疵的就是“验证算法的正确性”,说服力还是有点牵强~

旅行商问题 & 广义旅行商问题

旅行商问题( TSP ):即为在赋权图 G 上找一条费用最小的 Hamilton 回路, 即一条能够遍历图中的一切顶点, 而且起点与终点重合的路

广义旅行商问题(GTSP): 中, 顶点集 V 变为 p 个点群( cluster ) 的并集, V=V 1 ∪V 2 ∪…∪V p , 目标是要找到一条能够遍历p 个点群的费用最小的 Hamilton 回路


思考

这道题在一开始看来会觉得有点不像GTSP问题,但是仔细想了一下又好像是了。

举个例子Q1->Q2的最短距离,中间经过了许多的点,而这些点可以看做是Q1,Q2的点集,Q1,Q2就相当于是个点群(其中不包含查询集合Q中的点(除了Q1,Q2),且不包含S,T起点终点)。至于点群中的点,有没有重复经过我们不关心,我们只需要确保这些点群我们只经历过1次,这便足矣。

那么要做的有2部分。一,寻找最短路径 二,动态规划找最优解


过程

1.读取文件

下载图文件发现一共有200w个顶点,这相当于2^21量级。若使用矩阵来进行图的存储,会发现就算是使用char(1byte)来进行存储,也有2^21 * 2^21 = 2^42 (相当于4000 G)的大小。这条路行不通。

一开始构建图就开始遇到难题了,这要如何解决呢?

观察该文件一共有5,533,213 共有550w条弧(这里我把它当做是一个有向图了,不过还是维持了图的连通性,而且往返代价不一也挺符合现实的,算是误打误撞)

那就只能使用邻接表进行图的存储。
定义struct结构

struct Node{
        char weight;                //0-128节省空间
        int nodeID;              //连通点下标
         Node *next;
};//大小为12byte

则存储图的空间大小为
5.55 * 10^6 * 12 byte = 6.66 * 10^7 byte ≈ 66.6 MB左右
伪代码:

void loadGraph(char *filePath) {
        initNodeList();
        while(!endOfFile()){
            read(start,end);
            createRandomDataForNode();
            nodeID = end;
            insertintoNodeList(start);
        }
}//reading completed

使用邻接链表这就代表着之后在查找的时候会比较的久,好在该图每个点的出度平均只有2.5。查找不会太费时。

2.Dijkstra算法寻找最短路径

INITIALIZE
S=∅
Q=G.V
while Q≠∅
    u = EXTRACT-MIN(Q);         //查找点集V – S 中找到最短路径
    S = S ∪ {u}
for each vertex v ∈ G.Adj[u]
    RELAX(u,v,w)                
    //松弛操作:更新最短路径,其中需要增加一些判断条件以排除Q –{end}中的点。
                                //一旦找到了start->end的最短路径就退出。

集合S:从源结点s到该集合中每个结点之间的最短路径已经被找到。
集合Q:存放所有的结点集合
EXTRACTMIN(Q):算法不断的从结点集Q(V - S)中选择最短路径估计值最小的结点u,
S = S ∪ {u}: 并把u加入到集合S中。
RELAX(u,v,w):对所有从u点发的边进行“松弛”

If v.d > u.d + w(u,v)
        v.d = u.d + w(u,v)
        v.piror = u;

验证算法的正确性:

查看图文件发现0->5之间只有3条路径,刚好可以用来测试算法是否会找到最短路径
取开始点为0,结束点为5,进行简单的测试。经过Dijkstra算法计算以后,得到最短路径: 0 -> 1 -> 6 -> 5, 最小开销为177

控制台输出的Graph为图~ 以链表的形式展示
这里写图片描述
按照输出的权值画出图(只画出了主要的部分,其余无关的省略……)
这里写图片描述
在3条路径之中,

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值