最短路径
1.Floyd-Warshall算法 多源最短路径
算法思想:通过比较通过其他1,2,条边到达终点的距离来更新
用邻接矩阵存储后:
核心代码:
for(int k=1;k<=n;k++)
{
for(int i=1;i<=n;i++)
for(int j=1;j<=n;j++)
{
if(a[i][j]>a[i][k]+a[k][j])
a[i][j]=a[i][k]+a[k][j];
}
}
2.Dijkstra算法 单源最短路(无法解决负权边)
需要一个辅助数组dis来存储起点到其他所有点的距离
将dis数组中的值称为最短路程的"估计值"
核心思想:通过边来松弛起点到其他各个点的距离
代码;
//初始化dis数组
for(int i=1;i<=n;i++)
dis[i]=a[1][i](假设起点为1)
//标记数组初始化visted
for(int i=1;i<=n;i++)
visted[i]=0;
visted[1]=1;
//接下来重复过程
在dis数组中找当前离起点最近的点
然后访问这个点的所有边看是否能通过dis数组更新起点到那些边的距离
能的话就更新
代码:(部分是伪代码)
int min=Inf;
for(int i=1;i<=dis.size();i++)
{
if(dis[i]<min)
{
min=dis[i];
mark=i ;//mark用来记录这一点
}
}
然后更新:
for(int v=1;v<=n;v++)
{
if(a[mark][v]<inf)
{
if(dis[v]>dis[mark]+a[mark][v])
dis[v]=dis[mark]+a[mark][v];
}
}
这个过程持续n-1所以最外层还要加上循环
for(int k=1;k<=n-1;k++)
{
….
}
时间复杂度O(n^2)
3.Bellman-Ford算法-解决负权边
有dis数组 对所有边进行n-1次松弛操作
核心代码:
for(k=1;k<=n-1;k++)
for(i=1;i<=m;i++)
if(dis[v[i]]>dis[u[i]]+w[i])
dis[v[i]]=dis[u[i]]+w[i];
O(NM)
可以用check标记检测若dis数组已经不再更新就跳出循环
问题描述
给定一个n个顶点,m条边的有向图(其中某些边权可能为负,但保证没有负环)。请你计算从1号点到其他点的最短路(顶点从1到n编号)。
输入格式
第一行两个整数n, m。
接下来的m行,每行有三个整数u, v, l,表示u到v有一条长度为l的边。
输出格式
共n-1行,第i行表示1号点到i+1号点的最短路。
样例输入
3 3
1 2 -1
2 3 -1
3 1 2
样例输出
-1
-2
数据规模与约定
对于10%的数据,n = 2,m = 2。
对于30%的数据,n <= 5,m <= 10。
对于100%的数据,1 <= n <= 20000,1 <= m <= 200000,-10000 <= l <= 10000,保证从任意顶点都能到达其他所有顶点
来自 <http://lx.lanqiao.cn/problem.page?gpid=T15>
#include<iostream>
using namespace std;
const int Inf=99999999;
const int maxn=200010;
int u[maxn],v[maxn],w[maxn];
int main() {
int n,m;
while(cin>>n>>m) {
for(int i=1; i<=m; i++)
cin>>u[i]>>v[i]>>w[i];
int *dis=new int [n+1];
for(int i=1; i<=n; i++)
dis[i]=Inf;
dis[1]=0;
int check;
for(int i=1; i<=n-1; i++) {
check=0;
for(int j=1; j<=m; j++)
if(dis[v[j]]>dis[u[j]]+w[j])
{
dis[v[j]]=dis[u[j]]+w[j];
check=1;
}
if(check==0)
break;
}
for(int i=2; i<=n; i++)
cout<<dis[i]<<endl;
}
return 0;
}