- 基本介绍
- 模板题目
- 代码实现
基本介绍
求最短路径是挺重要的一个图论基础知识一般的话有这几种方法:Floyed Dijkstra SPFA(和Ford)差不多…
Dij我没有学 只学了Floyed和SPFA 所以先说这两个
Floyed
最简单的方法 适用于负边权 适用于任何路径
但是也正是因为它太简单了 所以O(n^3)的复杂度成为了它的致命缺点 基本上都没法用这个..
核心代码:
for(int k=1;k<=n;k++){
for(int i=1;i<=n;i++){
for(int j=1;j<=n;j++){
if(i!=j&&i!=k&&j!=k){
map[i][j]=min(map[i][j],map[i][k]+map[k][j]);
}
}
}
}
三重循环更新 i 到 j 的最短距离 中间做一个中间点 k (注意k的循环一定在最外层)来寻找最短路
因为时间复杂度太高 所以一般不用Floyed求解最短路 但是判两点是否联通是比较常用的
SPFA
好了 这个是一个好方法了 首先感谢-Qiu.YF-给我快速讲了一遍数组模拟邻接表储存 以后会写博客记录 先说SPFA 需要队列
它的时间复杂度只有O(kE) k是一个常数(据说平均数是2) E是边数
初始时将起点加入队列 每次从里面取出一个元素 修改相邻的点 修改成功就入队(反正我也不太懂) 总体在形式上有点像BFS 但是SPFA的一个点可能在它进入了队列之后再进被放进队列 也就是一个点在修改了其他的点之后 可能会获得更短的路径 从而再修改其它的点 这样反复进行下去直到都是最短路径.(听起来就比Floyed高级很多)
这个方法(貌似)需要很多邻接表的知识 我也是现补的
这是一段代码 以后有博客专门说数组模拟邻接表储存
inline void add(int from,int to,int dis)
{
edge[++num].next=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
这段代码实际上就是用来存储的 然后就是核心代码
while(h<t){ //当头指针和尾指针指在同一个地方的时候就结束了
h++; //头指针向下移一位 取出下一个指向的点
exist[team[h]]=false; //false就带表这个点被取出来了
for(int i=head[team[h]];i!=0;i=edge[i].next){ //遍历所有与这个被取出的点相连的边
if(dis[team[h]]+edge[i].dis<dis[edge[i].to]){
dis[edge[i].to]=dis[team[h]]+edge[i].dis;
if(!exist[edge[i].to){ //如果队列中不存在这个点 就让它入队
exist[edge[i].to]=true;
team[++t]=edge[i].to; //尾指针下移一位 这个点就入队了
}
}
}
}
用这种队列的方式可以大大的减少队列长度
这大概就是SPFA了 以后会再弄的明白一点…
模板题目
题目描述
给出一个有向图,请输出从某一点出发到所有点的最短路径长度。
输入输出格式
输入格式:
第一行包含三个整数N、M、S,分别表示点的个数、有向边的个数、出发点的编号。
接下来M行每行包含三个整数Fi、Gi、Wi,分别表示第i条有向边的出发点、目标点和长度。
输出格式:
一行,包含N个用空格分隔的整数,其中第i个整数表示从点S出发到点i的最短路径长度(若S=i则最短路径长度为0,若从点S无法到达点i,则最短路径长度为2147483647)
输入输出样例
输入样例:
4 6 1
1 2 2
2 3 2
2 4 1
1 3 5
3 4 3
1 4 4
输出样例:
0 2 4 3
这个题吧Floyed的肯定做不了 数组开大了爆零RE 也反映了Floyed的局限性真的很大 那么就用SPFA做
代码实现
#include<iostream>
#include<cstring>
#include<string>
using namespace std;
#define size 500005
int n,m,s;
int x,y,z;
int num;
int head[size],team[size],dis[size];
int h,t=1;
bool exist[size];
struct edge{
int to;
int dis;
int next;
}edge[size];
inline void add(int from,int to,int dis)
{
edge[++num].next=head[from];
edge[num].to=to;
edge[num].dis=dis;
head[from]=num;
}
inline void work()
{
for(int i=1;i<=m;i++){
cin>>x>>y>>z;
add(x,y,z);
}
while(h<t){
h++;
exist[team[h]]=false;
for(int i=head[team[h]];i!=0;i=edge[i].next){
if(dis[team[h]]+edge[i].dis<dis[edge[i].to]){
dis[edge[i].to]=dis[team[h]]+edge[i].dis;
if(!exist[edge[i].to]){
exist[edge[i].to]=true;
team[++t]=edge[i].to;
}
}
}
}
for(int i=1;i<=n;i++){
if(dis[i]==dis[0]){
cout<<"2147483647"<<" ";
}
else {
cout<<dis[i]<<" ";
}
}
}
inline void input()
{
memset(dis,127/3,sizeof(dis));
cin>>n>>m>>s;
dis[s]=0;
team[1]=s;
}
int main()
{
input();
work();
}
//COYG
一个裸SPFA 数组要开的大一点 其实完全可以不用结构体的 被同学带的用了结构体 但是感觉 有点乱
Floyed的话其实能拿30分
end.