求最短路一般有四种方法:
1.floyd dp思想dis[i][j]=min(dis[i][j]+dis[i][k]+dis[k][j]) 时间复杂度O(N^3)
2.dijkstra 邻接矩阵。 时间复杂度O(N^2)
3.dijkstra 邻接表+优先级队列优化。 时间复杂度O(M*lgN)
4.bellman-Ford 用于解决含有负权值得最小路问题 时间复杂度O(M*N)5.SPFA是bellman-ford的改进算法(队列实现),效率也更高 复杂度为:O(kE)E为边数,k一般为2或3
1.floyd算法:可以求任意两点之间的最短距离。解决传递背包和最小环问题~,不能解决负权回路。
for(int k=0;k<a;k++)//经过k点 { for(int i=0;i<a;i++)//起点 { for(int j=0;j<a;j++)//终点 { If(w[i][j]>w[i][k]+w[k][i]; w[i][j]=w[i][k]+w[k][i]; } } }//如果经过k点距离变短,那么w[i][j]不变,否则更新。
可以理解为对于1点而言,经过或者不经过1点求个最短,然后在1点的基础上对于2点,求个最短路...。2.dijkstra 邻接矩阵:没办法解决负边权的最短路径。
采用的是邻接矩阵来存的,第一点浪费的空间比较多,第二点我们知道算法的时间复杂度在O(n*n)
(1)确定数组—邻接矩阵(赋值0或者inf)
(2)输入数组-邻接矩阵
(3)确定距离dis数组//用1号顶点到其余各边的距离初始化;
(4)判断某一点是否当过起始点bool数组
(5)最关键!!循环n-1次,
先找一行中的最小值确保该行没有遍历过。
找到之后通过最小值所在行更新dis数组。
//初始化
for(i=1;i<=n;i++)
for(j=1;j<=n;j++)
if(i==j) e[i][j]=0;
else e[i][j]=inf;
//读入边和权值
for(i=1;i<=m;i++)
{
scanf("%d %d %d",&t1,&t2,&t3);
e[t1][t2]=t3;
}
//初始化dis数组,这里是1号顶点到其余各个顶点的初始路程
for(i=1;i<=n;i++)
dis[i]=e[1][i];
//book数组初始化
for(i=1;i<=n;i++)
book[i]=0;
book[1]=1;
//Dijkstra算法核心语句
for(i=1;i<=n-1;i++)//循环n-1次,每次都找到一行中的最小值,也就是对应的最小的点。
{
min=inf;
for(j=1;j<=n;j++)//找离某一点最近的点
{
if(book[j]==0 && dis[j]<min)
{
min=dis[j];
u=j;
}
}
book[u]=1;
for(v=1;v<=n;v++)//找到最小点的最小距离的点,有的话就更新。
{
if(e[u][v]<inf)
{
if(dis[v]>dis[u]+e[u][v])
dis[v]=dis[u]+e[u][v];
}
}
}
3.dijkstra 邻接表+优先级队列优化。
重载一个比较函数
struct node{ int x,d; node(){} node(int a,int b){x=a;d=b;} bool operator < (const node & a) const { if(d==a.d) return x<a.x; else return d > a.d; } }; //定义一个结构体,重载比较函数
- vector<node> eg[Ni];
- int dis[Ni],n;
void Dijkstra(int s) { int i; for(i=0;i<=n;i++) dis[i]=INF; dis[s]=0; //用优先队列优化 priority_queue<node> q; q.push(node(s,dis[s])); while(!q.empty()) { node x=q.top();q.pop(); for(i=0;i<eg[x.x].size();i++) { node y=eg[x.x][i]; if(dis[y.x]>x.d+y.d) { dis[y.x]=x.d+y.d; q.push(node(y.x,dis[y.x])); } } } }
4.bellman-Ford一:初始化所有点。每一个点保存一个值,表示从原点到达这个点的距离,将原点的值设为0,其它的点的值设为无穷大(表示不可达)。二:进行循环,循环下标为从1到n-1(n等于图中点的个数)。在循环内部,遍历所有的边,进行松弛计算。三:遍历途中所有的边(edge(u,v)),判断是否存在这样情况: d(v) > d (u) + w(u,v) 则返回false,表示途中存在从源点可达的权为负的回路。
struct node{
int from,to,w;
};
node edge[100];
bool Ford()
{
for(i = 1; i <= n; i ++)
dis[i] = inf;
dis[1] = 0;
for(i = 1; i <= n; i ++)
{
flag = false;
for(j = 1; j <= m; j ++)
{
x = edge[i].from ;
y = edge[i].to ;
z = edge[i].w ;
if(dis[y] > dis[x] + z)
{
dis[y] = dis[x] + z;
flag = true;
}
}
if(!flag)
break;
//如果更新到n遍,还能够继续更新dis数组,说明存在负权环
if(flag&&i == n)
return false;//返回false表示这个图存在负权环
}
return true;//返回true表示求最短路成功
}
5.SPFA