首先是邻接表形式的Bellman_Ford算法,他的复杂度是O(|E||V|),他的优势在于可以计算有负边存在的情况
struct edge{int from,to,cost;};
int r,n;//r代表边的数量,n代表点的数量
edge E[maxr];
int d[maxn];
void Bellman_ford(int s){
fill(d,d+n,INF);
d[s]=0;
while(true){
bool update=false;
for(int i=0;i<r;i++){
edge t=E[i];
if(d[t.from]!=INF && d[t.to] > d[t.from] + t.cost){
d[t.to]=d[t.from] + t.cost;
update=true;
}
//这是无向图情况下的添加的更新,如果是有向图就不需要这一步
if(d[t.to]!=INF && d[t.from] > d[t.to] + t.cost){
d[t.from]=d[t.to] + t.cost;
update=true;
}
}
if(!update) break;
}
return;
}
int main(){
cin >> r >> n;
for(int i=0;i<r;i++){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
x--;y--;
E[i]=(edge){x,y,val};
}
Bellman_ford(0);
cout << d[n-1] << endl;
return 0;
}
接下来是邻接矩阵形式的dijkstra算法,他的复杂度是O(|v|^2),复杂度上这个和上面的算法都差不多,但是他不能计算有负边的情况。相对于优先队列优化过的dijkstra算法他要好写很多。
int r,n;
int cost[maxn][maxn],d[maxn];
bool used[maxn];
void dijkstra(int s){
fill(d,d+n,INF);
fill(used,used+n,false);
d[s]=0;
while(true){
int v=-1;
for(int i=0;i<n;i++)
//从剩下的点中寻找出最短距离的点
if(!used[i] && (v==-1 || d[i]<d[v])) v=i;
if(v==-1) break;//如果所有的点都不可以选那么就退出
used[v]=true;
for(int i=0;i<n;i++)//更新所有点的最短距离
d[i]=min(d[i],d[v]+cost[v][i]);
}
return;
}
int main(){
cin >> r >> n;
//注意点之间的花费如果题中没有那么就是INF
for(int i=0;i<maxn;i++)
for(int j=0;j<maxn;j++)
cost[i][j]=INF;
while(r--){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
x--;y--;
if(cost[x][y]>val){//有的题中需要考虑重边的情况,但是前面和后面的两种算法可以不用考虑重边的情况
cost[x][y]=val;
cost[y][x]=val;
}
}
dijkstra(0);
cout<<d[n-1]<<endl;
return 0;
}
下面是用优先队列优化过的dijkstra算法,他的复杂度是O(|E|log|V| )
typedef pair<int,int> p;
struct edge{int to,cost;};
int n,r;
vector<edge> E[maxn];//存储与其相连的所有顶点
int d[maxn];
void dijkstra(){
fill(d,d+n,INF);
d[0]=0;
priority_queue< p,vector<p>,greater<p> > que;//设置一个小值优先的优先队列
que.push(p(0,0));
while(!que.empty()){
p now=que.top();que.pop();
int dist=now.first,v=now.second;
if(dist > d[v]) continue;//这个时候就没必要更新了
int len=E[v].size();
for(int i=0;i<len;i++){//列举所有顶点,自身更新后将还可以更新的点入队
edge t=E[v][i];
int newdist=t.cost + d[v];
if(newdist < d[t.to]){
d[t.to]=newdist;
que.push(p(d[t.to],t.to));
}
}
}
return;
}
int main(){
cin >> r >> n;
while(r--){
int x,y,val;
scanf("%d%d%d",&x,&y,&val);
x--;y--;
E[x].push_back( (edge){y,val} );
E[y].push_back( (edge){x,val} );
}
dijkstra();
cout << d[n-1] << endl;
return 0;
}
最后还有一种可以知道任意两点间的最短路的Floyd_warshall算法,他的优点在于不是像前面两种算法一样只能计算从0点到n点的最短路,而是可以计算任意两点间的最短路径,而且写起来非常的简单。当然将上面两个算法调整s值后也可以实现这样的功能,而且复杂度更低,所以这种算法很不常用。
int d[maxn][maxn];//d[u][v]代表边e =(u,v)的权值,不存在时设为INF,不过d[i][i]=0
int n;
void Floyd_warshall(){
for(int k=0;k<n;k++)
for(int i=0;i<n;i++)
for(int j=0;j<n;j++)
d[i][j]=min(d[i][j],d[i][k] + d[k][j]);
}