洛谷有题
P3371 【模板】单源最短路径(弱化版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
先放大佬的ac代码(请看第一篇题解,写的很不错!)
P4779 【模板】单源最短路径(标准版) - 洛谷 | 计算机科学教育新生态 (luogu.com.cn)
Floyd算法是求任意两点的最短路径
(5条消息) 《算法笔记》—— 图 "最短路径" 之 Floyd-Warshall算法、Diljkstra算法_浪子花梦-CSDN博客
dijkstra手工
邻接矩阵方法
考试必要理解的diljkstra(模板),老师给的
/*
* 单源最短路径,Dijkstra算法,邻接矩阵形式,复杂度为O(n^2)
* 求出源beg到所有点的最短路径,传入图的顶点数,和邻接矩阵cost[][],n为结点个数
* 返回各点的最短路径dist[], 路径path[].path[i]记录beg到i路径上的父结点,path[beg]=-1
* 可更改路径权类型,但是权值必须为非负
*
*/
const int MAXN=1010;
#define typec int
const typec INF=0x3f3f3f3f;//防止后面溢出,这个不能太大
bool vis[MAXN]; //判断顶点所属集合标志数组
int path[MAXN]; //双亲数组 记录路径
void Dijkstra(typec cost[][MAXN],typec dist[],int n,int beg)
{
for(int i=0;i<n;i++) //初始化,使得每一条路径最大,n为顶点数
{
dist[i]=INF;
vis[i]=false; //这个数组记录未被访问的结点,后续判断要用
path[i]=-1;
}
dist[beg]=0; //起点到起点路径为0
for(int j=0;j<n;j++) //
{
int k=-1;
int Min=INF;
for(int i=0;i<n;i++) //先找出最小的未访问的最小顶点k
if(!vis[i]&&dist[i]<Min)
{
Min=dist[i]; //一直循环找最小
k=i;
}
if(k==-1) //如果把所有的dist遍历一遍都找到了最短路径,则退出循环结束
break;
vis[k]=true; //将新找到的当前最小结点设置为“已访问”
/*
此时将当前最小结点置入dist后,更新所有从k结点出发到任意一顶点的路径(松弛),
这时候可以把下一个结点的最短路径求出
*/
for(int i=0;i<n;i++)
if(!vis[i] && dist[k]+cost[k][i]<dist[i]) //松弛
{
dist[i]=dist[k]+cost[k][i];
path[i]=k; //每次可以通过这个pre找到上一个最短路径从而接上去
}
}
怎么打印路径以及邻接表的dijikstra算法在下面的一个博客可以找到答案
(5条消息) Dijkstra基于邻接表算法C++实现_优雅~天宫雁-CSDN博客
———————————————————————————————————————————更新:偶然在书上看到了如何打印path的方法,特意写出来
template<class T , class E>
void printShotestPath(Graph<T,E>& G,int beg,E dist[],int path[]){
cout<<"从顶点"<<G.getValue(beg)<<"到其他顶点的最短路径为:"<<endl;
int i,j,k;
int n=G.NumberOfVertices(); //获取顶点个数!
int *d=new int[n]; //开辟临时存放路径的容器
for(i=0;i<n;i++){ //对每一个dist结点进行遍历
if(i!=beg){ //其实这个if可以省略,改动for循环从1开始
j=i;k=0; //k记录路径通过多少个结点,每次循环都会重置一次
while(j!=v){ //当j=v时,则找结点找回到路径起点,结束循环
d[k++]=j;
j=path[j];
}
//正常输出结点,注意是逆序
cout<<"顶点"<<G.getValue(i)<<"的最短路径为:"<<G.getValue(beg);
while(k>0){
cout<<G.getValue(d[--k])<<" ";
}
cout<<"最短路径长度为:"<<dist[i]<<endl;
}
}
delete []d;
};
弗洛伊德算法求最短路径
(11条消息) 弗洛伊德(Floyd)算法求图的最短路径_刘剑峰的博客-CSDN博客_floyd算法求最短路径
//这里是弗洛伊德算法的核心部分
//k为中间点
for(k = 0; k < G.vexnum; k++){
//v为起点
for(v = 0 ; v < G.vexnum; v++){
//w为终点
for(w =0; w < G.vexnum; w++){
if(D[v][w] > (D[v][k] + D[k][w])){
D[v][w] = D[v][k] + D[k][w];//更新最小路径
P[v][w] = P[v][k];//更新最小路径中间顶点 ,打印路径要用
}
}
}
}
求路径
v = 0;
w = 3;
//求 0 到 3的最小路径
printf("\n%d -> %d 的最小路径为:%d\n", v, w, D[v][w]);
k = P[v][w];
printf("path: %d", v);//打印起点
while(k != w){
printf("-> %d", k);//打印中间点
k = P[k][w];
}
printf("-> %d\n", w);