问题描述
广义旅行商问题:给定一个加权图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条路径之中,