一:单源最短路
1:Bellman-Ford算法
/**
单源最短路问题(Bellman-Ford算法)
输入
5 6
0 1 2
1 2 1
2 3 4
3 4 3
0 4 5
0 3 2
输出
3
**/
#include<stdio.h>
#include<iostream>
#define INF 9999999
using namespace std;
struct edge{
int from,to,cost;
};
edge es[100]; //边
int d[100]; //最短距离
int V,E; //V是顶点数,E是边数
//求解从节点S出发到所有点的最短距离
void shortest_path(int s){
for(int i=0;i<V;i++){
d[i]=INF;
}
d[s]=0;
while(true){
bool update =false;
//寻找起点不是INF,而且终点到源点权值大于起点到源点权值加上边权值的边
for(int i=0;i<E;i++){
edge e=es[i];
if(d[e.from]!=INF&&d[e.to]>d[e.from]+e.cost){
d[e.to]=d[e.from]+e.cost;
update=true;
}
}
if(!update){
break;
}
}
}
int main(){
int from,to,cost;
scanf("%d%d",&V,&E);
//边数为E但需要2*E个存储无向图
E=E*2;
for(int i=0;i<E;i=i+2){
scanf("%d%d%d",&from,&to,&cost);
es[i].from=from;
es[i].to=to;
es[i].cost=cost;
es[i+1].from=to;
es[i+1].to=from;
es[i+1].cost=cost;
}
//假如从2点出发,求到0点最短距离
shortest_path(2);
printf("%d",d[0]);
return 0;
}
2:dijkstra算法
/**
单源最短路问题(dijkstra算法)
输入
5 6
0 1 2
1 2 1
2 3 4
3 4 3
0 4 5
0 3 2
输出
3
**/
#include<stdio.h>
#include<algorithm>
#include<cstring>
#define INF 999999
using namespace std;
int cost[100][100]; //cost[u][v]表示边u,v的权值,不存在时设为INF
int d[100];//顶点S出发的最短距离
bool used[100]; //已经使用过的图
int V,E; //定点数
//求从起点s出发的最短距离
void dijkstra(int s){
fill(d,d+V,INF);
fill(used,used+V,false);
d[s]=0;
while(true){
int v=-1;
//从未使用过的顶点中选择一个距离最小的顶点
for(int u=0;u<V;u++){
if(!used[u]&&(v==-1||d[u]<d[v])){
v=u;
}
}
if(v==-1){
break;
}
used[v]=true;
for(int u=0;u<V;u++){
d[u]=min(d[u],d[v]+cost[v][u]);
}
}
}
int main(){
int tempx,tempy,co;
scanf("%d%d",&V,&E);
//边权初始化为INF
for(int i=0;i<V;i++)
for(int j=0;j<V;j++){
cost[i][j]=INF;
}
for(int i=0;i<E;i++){
scanf("%d%d%d",&tempx,&tempy,&co);
cost[tempx][tempy]=co;
cost[tempy][tempx]=co;
}
//假如从2点出发,求到0点最短距离
dijkstra(2);
printf("%d\n",d[0]);
return 0;
}
3:dijkstra算法优化
/**
单源最短路问题(dijkstra算法优化)
输入
5 6
0 1 2
1 2 1
2 3 4
3 4 3
0 4 5
0 3 2
输出
3
**/
#include<stdio.h>
#include<vector>
#include<iostream>
#include<queue>
#include<algorithm>
#define INF 9999999
using namespace std;
typedef pair<int ,int> P; //first是最短距离,second是顶点
struct edge{
int to,cost;
};
int V,E;//V是顶点数,E是边数
vector<edge> G[100];
int d[100];
void dijkstra(int s){
//通过greater<p>参数,堆按照从大到小的顺序取出值
priority_queue<P,vector<P>,greater<P> >que;
fill(d,d+V,INF);
d[s]=0;
que.push(P(0,s));
while(!que.empty()){
P p=que.top();
que.pop();
int v=p.second;
if(d[v]<p.first){
continue;
}
for(int i=0;i<G[v].size();i++){
edge e=G[v][i];
if(d[e.to]>d[v]+e.cost){
d[e.to]=d[v]+e.cost;
que.push(P(d[e.to],e.to));
}
}
}
}
int main(){
int from,to,cost;
scanf("%d%d",&V,&E);
for(int i=0;i<E;i++){
edge tempe1,tempe2;
scanf("%d%d%d",&from,&to,&cost);
tempe1.to=to;
tempe1.cost=cost;
G[from].push_back(tempe1);
tempe2.to=from;
tempe2.cost=cost;
G[to].push_back(tempe2);
}
//假如从2点出发,求到0点最短距离
dijkstra(2);
printf("%d\n",d[0]);
return 0;
}
二:多源最短路
/**
多源最短路问题(Floyd-Warshall算法)
输入
5 6
0 1 2
1 2 1
2 3 4
3 4 3
0 4 5
0 3 2
输出
3
**/
#include<stdio.h>
#include<iostream>
#include<algorithm>
#define INF 9999999
using namespace std;
int d[100][100]; //d[u][v]表示边uv的权值 (不存在时设为INF,但是d[i][i]为0)
int V,E; //V顶点数,E边数
void warshall_floyd(){
for(int k=0;k<V;k++){
for(int i=0;i<V;i++){
for(int j=0;j<V;j++){
d[i][j]=min(d[i][j],d[i][k]+d[k][j]);
}
}
}
}
int main(){
scanf("%d%d",&V,&E);
for(int i=0;i<V;i++)
for(int j=0;j<V;j++){
if(i==j){
d[i][j]=0;
}else{
d[i][j]=INF;
}
}
for(int i=0;i<E;i++){
int tempx,tempy,tempco;
scanf("%d%d%d",&tempx,&tempy,&tempco);
d[tempx][tempy]=tempco;
d[tempy][tempx]=tempco;
}
warshall_floyd();
//假如从2点出发,求到0点最短距离
printf("%d\n",d[2][0]);
return 0;
}
三:路径还原
用prev数组记录最短路径前驱节点
/**
还原路径问题(dijkstra算法)
输入
5 6
0 1 2
1 2 1
2 3 4
3 4 3
0 4 5
0 3 2
输出
3
**/
#include<stdio.h>
#include<algorithm>
#include<vector>
#define INF 999999
using namespace std;
int cost[100][100]; //cost[u][v]表示边u,v的权值,不存在时设为INF
int d[100];//顶点S出发的最短距离
bool used[100]; //已经使用过的图
int V,E; //定点数
int prev[100]; //最短路的前驱节点
//求从起点s出发的最短距离
void dijkstra(int s){
fill(d,d+V,INF);
fill(used,used+V,false);
fill(prev,prev+V,-1);
d[s]=0;
while(true){
int v=-1;
//从未使用过的顶点中选择一个距离最小的顶点
for(int u=0;u<V;u++){
if(!used[u]&&(v==-1||d[u]<d[v])){
v=u;
}
}
if(v==-1){
break;
}
used[v]=true;
for(int u=0;u<V;u++){
if(d[u]>d[v]+cost[v][u]){
d[u]=d[v]+cost[v][u];
prev[u]=v;
}
}
}
}
//到顶点t的最短路
vector<int> get_path(int t){
vector<int> path;
for(;t!=-1;t=prev[t]){
path.push_back(t);//不断沿着prev[t]走直到t=s
}
//这样得到的t-s,所以反转
reverse(path.begin(),path.end());
return path;
}
int main(){
int tempx,tempy,co;
scanf("%d%d",&V,&E);
//边权初始化为INF
for(int i=0;i<V;i++)
for(int j=0;j<V;j++){
cost[i][j]=INF;
}
for(int i=0;i<E;i++){
scanf("%d%d%d",&tempx,&tempy,&co);
cost[tempx][tempy]=co;
cost[tempy][tempx]=co;
}
//假如从2点出发,求到0点最短距离和路径
dijkstra(2);
printf("%d\n",d[0]);
vector<int> path=get_path(0);
for(int i=0;i<path.size();i++){
printf("%d ",path[i]);
}
return 0;
}