Dijkstra算法
Dijkstra算法是一种单源最短路径算法,本质是贪心,只适用于没有负权边的图,并且不能用以计算最长路径
时间复杂度:?(?^2 )
优秀文章推荐:https://blog.csdn.net/qq_35644234/article/details/60870719
拓展:Dijkstra算法可以使用堆优化,优化后的效率是: 时间复杂度:?((?+?) log ?)(m为边数,n为顶点数) 堆优化的Dijkstra算法更适用于稀疏图
#include <iostream>
#define INF 0x3f3f3f
#include <cstring>
using namespace std;
int N,M,S,T;
int graph[1005][1005];
bool vis[1005];
int dis[1005];
void Dijkstra()
{
memset(vis,false,sizeof(vis));
for(int j = 1; j <= N; j++ )
dis[j] = graph[S][j];
vis[S] = true;
dis[S] = 0;
for(int i = 0; i < N - 1; i++ )//找n - 1次
{
int minn = INF;
int u = S;//最小值的下标;
for(int j = 1; j <= N; j++ )//找出最小值
{
if(!vis[j] && minn > dis[j])
{
u = j;
minn = dis[j];
}
}
if(minn == INF)
break;
vis[u] = true;//已更新
for(int k = 1; k <= N; k++ )
if(!vis[k] && minn + graph[u][k] < dis[k])
dis[k] = minn + graph[u][k];
}
}
int main()
{
cin >> N >> M >> S >> T;
memset(graph,INF,sizeof(graph));
memset(dis,INF,sizeof(dis));
for(int i = 0, x, y, z; i < M; i++ )
{
cin >> x >> y >> z;
graph[x][y] = graph[y][x] = min(graph[x][y],z);
}
Dijkstra();
cout << dis[T];
}
Bellman-Ford算法
Bellman-Ford算法 同样为单源路径算法,和Dijkstra算法不同的是, Bellman-Ford算法可以计算最长路径,还可以处理负权 边,本质是动态规划
时间复杂度:?(??)
优秀文章推荐: https://blog.csdn.net/sms0101/article/details/73088422
注:使用Bellman-Ford算法处理带负权边的图时,要记得判断是否存在负环
例题同上
#include <iostream>
//bell-man ford
#include <cstring>
#define INF 0x3f3f3f3f
using namespace std;
int n,m,s,t;
struct edge
{
int from,to,len;
}edges[10005];
int dis[10005];
void Bell()
{
dis[s] = 0;
for(int i = 0; i < m; i++ )
if(edges[i].from == s)
dis[edges[i].to] = min(edges[i].len,dis[edges[i].to]);
else if(edges[i].to == s)
dis[edges[i].from] = min(dis[edges[i].from], edges[i].len);
while(1)
{
bool ok = false;//检查是否有松弛
for(int i = 0; i < m; i++ )
{
int u =edges[i].from;
int v =edges[i].to;
int l =edges[i].len;
if(dis[v] > dis[u] + l)
dis[v] = dis[u] + l, ok =true;
else if(dis[u] > dis[v] + l)
dis[u] = dis[v] + l, ok = true;
}
if(!ok)
break;
}
}
int main()
{
cin >> n >> m >> s >> t;
memset(dis,INF,sizeof(dis));
for(int i = 0; i <m; i++ )
cin >> edges[i].from >> edges[i].to >> edges[i].len;
Bell();
cout << dis[t];
}
Floyd算法
与前两者不同,Floyd算法用以计算图中所有两点间的最短或最长路径,本质也是动态规划,图的存储方式需为邻接矩阵
时间复杂度:?(?^3 )
优秀文章推荐: https://blog.csdn.net/qq_35644234/article/details/60875818
注:如果你喜欢的话,也可以对每个点都使用一次Dijkstra算法,但Floyd算法的代码可以只有仅仅4行
#include <iostream>
#include <cstring>
#define INF 0x3f3f3f
using namespace std;
int n, m;
int graph[105][105];
void Floyd()
{
for(int k = 1; k <= n; k++ )
for(int i = 1; i <= n; i++ )
for(int j = 1; j <=n; j++ )
graph[i][j] = min(graph[i][j],graph[i][k] + graph[k][j]);
}
int main()
{
cin >> n >> m;
memset(graph,INF,sizeof(graph));
for(int i = 0; i <= n; i++ )
graph[i][i] = 0;
for(int i = 0; i < m; i++ )
{
int x, y, z;
cin >> x >> y >> z;
graph[x][y] = graph[y][x] = min(z,graph[x][y]);
}
Floyd();
for(int i = 1; i <= n; i++ )
{
for(int j = 1; j <= n; j++ )
cout << graph[i][j] << " ";
cout << endl;
}
}
SPFA(Shortest Path Faster Algorithm)
SPFA其实是Bellman-Ford的队列优化版,所以适用情况与Bellman-Ford相同,平均效率比Bellman-Ford高
最坏情况时间复杂度: ?(??)
优秀文章推荐: https://blog.csdn.net/rentenglong2012/article/details/78483662
注:有些题目会针对SPFA,使SPFA遇到最坏情况,导致程序时间超限,所以选用SPFA时需要谨慎,可考虑用堆优化Dijk
#include <iostream>
#define INF 0x3f3f3f3f
#include <cstring>
#include <queue>
using namespace std;
int n,m,s,t;
int dis[100005];
int head[100005];
bool vis[100005];
queue<int> q;
struct edge
{
int from,to,len,next;
}edges[2000005];
void SPFA()
{
memset(dis,INF,sizeof(dis));
memset(vis,false,sizeof(vis));
q.push(s);
vis[s] = true;
dis[s] = 0;
while(!q.empty())
{
int u = q.front();
q.pop();
vis[u] = false;//
for(int i = head[u]; i >0; i = edges[i].next )
{
int v = edges[i].to;
int l = edges[i].len;
if(dis[v] > dis[u] + l)
{
dis[v] = dis[u] + l;
if(!vis[u])
{
q.push(v);
vis[v] = true;
}
}
}
}
}
int main()
{
cin >> n >> m >> s >> t;
for(int i = 0, cnt = 0; i < m; i++ )
{
int u,v,l;
cin >> u >> v >> l;
edges[cnt] = {u,v,l,head[u]};
head[u] = cnt++;
edges[cnt] = {v,u,l,head[v]};
head[v] = cnt++;
}
SPFA();
cout << dis[t];
}