标号法求解单源最短路径
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
......
标号法求解单源最短路径相关推荐
- Dijkstra算法求解单源最短路径问题
文章目录 一 前言 二 Dijkstra 算法讲解 1. 贪心算法的证明 2. 算法实现说明 3. 初版Dijkstra算法代码 三 时间复杂度优化 1. 优化策略 2. 优化后的代码 四 结语 一 ...
- 求解单源最短路径的几种算法
方法一:Dijkstra算法 #include<iostream> #include<algorithm> #include<cstring> #include&l ...
- 单源路径分支界限java_java单源最短路径算法
. .. .. . 单源最短路径的 Dijkstra 算法: 问题描述: 给定一... 并 应用贪心法求解单源最短路径问题.环境要求对于环境没有特别要求.对于算法实现,可以自由选择 C, C++, J ...
- 单源最短路径Dijkstra算法的思想、详细步骤、代码
目录 一.算法思想 二.算法详细步骤 三.伪代码 + C++代码 四.算法复杂度分析 五.算法改进 六.应用案例 一.算法思想 1.Dijkstra 算法是用来求解单源最短路径问题的经典算法,其本质上 ...
- 算法导论之单源最短路径
单源最短路径,在现实中是很多应用的,是图的经典应用,比如在地图中找出两个点之间的最短距离.最小运费等.单源最短路径的问题:已知图G=(V,E),找出给定源顶点s∈V到每个顶点v∈V的最短路径.单源最短 ...
- Dijkstra算法求单源最短路径
1.最短路径 在一个连通图中,从一个顶点到另一个顶点间可能存在多条路径,而每条路径的边数并不一定相同.如果是一个带权图,那么路径长度为路径上各边的权值的总和.两个顶点间路径长度最短的那条路径称为两个顶 ...
- 单源路径分支界限java_单源最短路径-分支界限法
单源最短路径-分支界限法-优先队列式.这里使用无回路的有向图,便于构建树.构建好树后,从根结点作为起始源,加入结点队列,然后判断获取队列中最短的路径结点做为活结点,将活结点的所有子结点加入队列,移除活 ...
- 四种不同单源最短路径算法性能比较
四种不同单源最短路径算法性能比较 一.最短路径问题描述 单源最短路径描述:给定带权有向图G=(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称之为源.现在要计算从源到其他各顶点的 ...
- 四种单源最短路径算法
一.最短路径问题描述 单源最短路径描述:给定带权有向图G=(V,E),其中每条边的权是非负实数.另外,还给定V中的一个顶点,称之为源.现在要计算从源到其他各顶点的最短路径的长度.这里的路径长度指的 ...
最新文章
- R语言使用tidyquant包的tq_transmute函数计算持有某只股票的天、月、周收益率、ggplot2使用条形图(bar plot)可视化股票年收益率数据使用不同的色彩表征正收益率和负收益率
- linux服务器LVS/DR模式+nfs
- QQ第三方登录报错error=-1
- Android 使用 ActivityResult 处理 Activity 之间的数据通信及调起拍照实例
- 使用VS2019开始第一个C语言程序,环境安装配置+代码实例
- python tfidf特征变换_使用sklearn提取文本的tfidf特征
- 让这家有12万名员工、1.7万种产品的钢铁厂平滑上云的黑科技是什么?
- 《落》用计算机弹,《大弦嘈嘈如急雨,小弦切切如私语.嘈嘈切切错杂弹,大珠小珠落玉盘.》什么意思|出处|翻译|用法例释...
- Time complexity analysis of algorithms
- plc tcp ip通讯怎么只能连一个客户端_Kepware V5如何实现与PLC的通讯
- 博弈的意思_身处博弈时代,我们更要读些历史
- 分享100个PHP源码整站系统,总有一款适合你
- 卡西欧计算机十进制换二进制,卡西欧计算机怎么把十进制转换二进制
- php实例三之网站浏览量统计
- 用一根网线连接两台计算机,并传输数据
- 每个人都可以做到:月入30000的秘籍!
- iText7高级教程之html2pdf——4.使用pdfHTML创建报告
- 去掉SecureCRT菜单栏上的打印按钮
- 1.华为分布式存储fusionstorage介绍
- Gitlab的branch与Tag的使用