1. 问题描述

给定一个图结构,包含n个点,e条边,求解源点 s 到汇点 t 的最短路径及长度,以及源点 s 到前1000个点的最短路径长度。

数据文件"union.txt",格式为:

start_id,end_id,weight,start_x,start_y,end_x,end_y
1,101043,540,567.988263,99.564119,567.988263,100.104119
......

2. 算法策略

算法模拟了标号法的求解过程。首先有一个优先队列,队列种中的元素为(点号,权值),初始状态把源点(权值为0)入队,然后不断进行BFS,从优先队列里取出权值最小的元素(如果访问过则重新取下一个元素),访问该元素,标记位置1,对其相邻的结点进行“松弛”,更新它们的当前权值,更新它们的距离数组dist和路径数组path,并将它们全部入队,进行下一轮操作,从队列中取元素......队列为空时路径求解完成。

需要注意的是,某个结点可能会多次入队,可能会被多次松弛,但只会被访问一次(由标记数组决定)。

由dist数组和path数组可得到源点 s 到任意一点 t 的最短路径及长度。求解完成后,dist数组本身即更新为最短路径长度。由于path[i]是i的前驱结点,可间接得到路径。

3. 优化操作

因为涉及大量数据的 I/O,为加快读写速度,使用C语法进行 I/O操作,而不用<fstream>,<sstream>,<iostream>中的流,可节约至少一半的 I/O 时间。初始化用memset代替循环初始化。另外加了实时进度显示与时间统计。

4. 代码实现

#include "stdio.h"
#include "windows.h"
#include <vector>
#include <queue>
#include <stack>
#include <ctime>
using namespace std;#define MAXN 195234 //0 1 ... 195233
#define MAXW 0x3f3f3f3f //最大权重typedef struct WNode{int id;int cur_w;bool operator<(const WNode& n)const{return cur_w>n.cur_w;}WNode(int id,int cur_w):id(id),cur_w(cur_w){}
}WNode;//Graph[i]中存放的是 与i号结点相邻的 结点们的编号j以及对应权重w, Graph[i]={pair<j,w>,...}
vector<pair<int,int> > Graph[MAXN];
bool visit[MAXN];
int path[MAXN];
int dist[MAXN];int s,t; //源点,汇点
clock_t start,finish;//读入文件进行初始化
bool Initialize(){printf("Input the starting point: ");scanf("%d",&s);printf("Input the ending   point: ");scanf("%d",&t);printf("\nInputing data...\n");start=clock();FILE* fp=fopen("union.txt","r");if(fp==NULL){printf("File open error./n");return -1;}int sid,tid,w;double sx,sy,tx,ty;fscanf(fp,"%*[^\n]%*c");//跳过第一行while(true){fscanf(fp,"%d,%d,%d,%lf,%lf,%lf,%lf",&sid,&tid,&w,&sx,&sy,&tx,&ty);Graph[sid].push_back(make_pair(tid,w));//printf("%d %d %d\n",sid,tid,w);if(sid%1000==0){printf("\r[%.2f%%]",sid/195233.0*100);fflush(stdout);}if(sid==195233){printf("\r[%.2f%%]",sid/195233.0*100);finish=clock();printf("\nData input successfully.\n");printf("Total time is %.2fs\n.",(double)(finish-start)/CLOCKS_PER_SEC);break;}}fclose(fp);return true;
}//求解最短路径
void ShortestPath(int s){printf("\nSolving shortest path...\n");start=clock();memset(path,0,sizeof(path));memset(visit,0,sizeof(visit));memset(dist,MAXW,sizeof(dist));  priority_queue<WNode> qu;qu.push(WNode(s,0));path[s]=0;dist[s]=0;int sumvisit=0;//记录进度while(!qu.empty()){WNode cur=qu.top();qu.pop();if(visit[cur.id])continue;visit[cur.id]=1;sumvisit++;if(sumvisit%500==0){printf("\r[%.2f%%]",sumvisit/195233.0*100);fflush(stdout);}for(int i=0;i<Graph[cur.id].size();i++){pair<int,int> tmp=Graph[cur.id][i];if(!visit[tmp.first]){  //将未访问过的入队qu.push(WNode(tmp.first,tmp.second+cur.cur_w));}if(tmp.second+cur.cur_w < dist[tmp.first]){  //松弛dist[tmp.first]=tmp.second+cur.cur_w;path[tmp.first]=cur.id;}}}printf("\r[100.00%%]\n");printf("Path solved successfully.\n");finish=clock();printf("Total time is %.2fs.\n",(double)(finish-start)/CLOCKS_PER_SEC);
}//显示路径,反向输出
void DispPath(int t){printf("\nPath from %d to %d:\n",s,t);printf("Shortest path length is %d.\n\n",dist[t]);stack<int> tmps;int j=t;while(j>0){tmps.push(j);j=path[j];}while(tmps.size()>1){printf("%d->",tmps.top());tmps.pop();}printf("%d\n",tmps.top()); //不输出最后一个箭头tmps.pop();
}//将源点 s 与前 10000 个点的最短距离输出到文件
void ToFile(){FILE* fp;char str[20];itoa(s,str,10);strcat(str,".txt");//生成文件名fp=fopen(str,"w");fprintf(fp,"start_id,end_id,dist\n");for(int i=1;i<=10000;i++){if(dist[i]!=0x3f3f3f3f)fprintf(fp,"%d,%d,%d\n",s,i,dist[i]);elsefprintf(fp,"%d,%d,NaN\n",s,i);}fclose(fp);
}int _tmain(int argc, _TCHAR* argv[])
{Initialize();  ShortestPath(s);ToFile();DispPath(t);return 0;
}

5. 运行结果

(1)最短路径(101->1):

(2)源点到前10000个点的距离:

start_id,end_id,dist
101,1,1436410
101,2,1302440
101,3,1334756
101,4,1334893
101,5,1293080
......

标号法求解单源最短路径相关推荐

  1. Dijkstra算法求解单源最短路径问题

    文章目录 一 前言 二 Dijkstra 算法讲解 1. 贪心算法的证明 2. 算法实现说明 3. 初版Dijkstra算法代码 三 时间复杂度优化 1. 优化策略 2. 优化后的代码 四 结语 一 ...

  2. 求解单源最短路径的几种算法

    方法一:Dijkstra算法 #include<iostream> #include<algorithm> #include<cstring> #include&l ...

  3. 单源路径分支界限java_java单源最短路径算法

    . .. .. . 单源最短路径的 Dijkstra 算法: 问题描述: 给定一... 并 应用贪心法求解单源最短路径问题.环境要求对于环境没有特别要求.对于算法实现,可以自由选择 C, C++, J ...

  4. 单源最短路径Dijkstra算法的思想、详细步骤、代码

    目录 一.算法思想 二.算法详细步骤 三.伪代码 + C++代码 四.算法复杂度分析 五.算法改进 六.应用案例 一.算法思想 1.Dijkstra 算法是用来求解单源最短路径问题的经典算法,其本质上 ...

  5. 算法导论之单源最短路径

    单源最短路径,在现实中是很多应用的,是图的经典应用,比如在地图中找出两个点之间的最短距离.最小运费等.单源最短路径的问题:已知图G=(V,E),找出给定源顶点s∈V到每个顶点v∈V的最短路径.单源最短 ...

  6. Dijkstra算法求单源最短路径

    1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶 ...

  7. 单源路径分支界限java_单源最短路径-分支界限法

    单源最短路径-分支界限法-优先队列式.这里使用无回路的有向图,便于构建树.构建好树后,从根结点作为起始源,加入结点队列,然后判断获取队列中最短的路径结点做为活结点,将活结点的所有子结点加入队列,移除活 ...

  8. 四种不同单源最短路径算法性能比较

    四种不同单源最短路径算法性能比较   一.最短路径问题描述 单源最短路径描述:给定带权有向图G=(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称之为源.现在要计算从源到其他各顶点的 ...

  9. 四种单源最短路径算法

      一.最短路径问题描述 单源最短路径描述:给定带权有向图G=(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称之为源.现在要计算从源到其他各顶点的最短路径的长度.这里的路径长度指的 ...

最新文章

  1. R语言使用tidyquant包的tq_transmute函数计算持有某只股票的天、月、周收益率、ggplot2使用条形图(bar plot)可视化股票年收益率数据使用不同的色彩表征正收益率和负收益率
  2. linux服务器LVS/DR模式+nfs
  3. QQ第三方登录报错error=-1
  4. Android 使用 ActivityResult 处理 Activity 之间的数据通信及调起拍照实例
  5. 使用VS2019开始第一个C语言程序,环境安装配置+代码实例
  6. python tfidf特征变换_使用sklearn提取文本的tfidf特征
  7. 让这家有12万名员工、1.7万种产品的钢铁厂平滑上云的黑科技是什么?
  8. 《落》用计算机弹,《大弦嘈嘈如急雨,小弦切切如私语.嘈嘈切切错杂弹,大珠小珠落玉盘.》什么意思|出处|翻译|用法例释...
  9. Time complexity analysis of algorithms
  10. plc tcp ip通讯怎么只能连一个客户端_Kepware V5如何实现与PLC的通讯
  11. 博弈的意思_身处博弈时代,我们更要读些历史
  12. 分享100个PHP源码整站系统,总有一款适合你
  13. 卡西欧计算机十进制换二进制,卡西欧计算机怎么把十进制转换二进制
  14. php实例三之网站浏览量统计
  15. 用一根网线连接两台计算机,并传输数据
  16. 每个人都可以做到:月入30000的秘籍!
  17. iText7高级教程之html2pdf——4.使用pdfHTML创建报告
  18. 去掉SecureCRT菜单栏上的打印按钮
  19. 1.华为分布式存储fusionstorage介绍
  20. Gitlab的branch与Tag的使用

热门文章

  1. jsd 多线程与socket网络通信
  2. Bitvise SSH Client 8.32下载
  3. MCE公司:黄芩苷通过激活肝脏 CPT1 酶改善饮食诱导的肥胖和脂肪肝病变
  4. Java中的空指针异常
  5. 按键精灵读取github page 网页,实现脚本远程控制功能
  6. no source Theme.AppCompat.Light的解决方法
  7. 在vue中使用3d-force-graph
  8. 爬虫实战2(上):爬取豆瓣影评
  9. python操作excel遇到一系列问题
  10. 类似京东商城客户端应用iOS源码