Floyd算法
处理多源最短路径问题,即任意两个点的最短路径
void Floyd(){
for(int k=0;k<n;k++){ //注意:k一定要放在最外层
for(int i=0;i<n;i++){
for(int j=0;j<n;j++){
if(dis[i][k]!=INF && dis[k][j]!=INF && dis[i][k]+dis[k][j] < dis[i][j]){
dis[i][j] = dis[i][k]+dis[k][j];
}
}
}
}
}
Dijkstra优先队列版
时间复杂度为O(N*logN)
处理单源最短路径问题,即一个特定点到其他各点的最短距离,且边权为非负。
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=110,INF=1e9;
int vis[maxn],d[maxn];
struct node{
int st,len;
bool operator <(const node &a)const{
return a.len < len; //从小到大 优先队列跟sort中的比较规则是反的,建议直接尝试来选择大于还是小于
}
};
vector<node> edge[maxn];
void Dijkstra(int s,int n){
fill(d,d+maxn,INF); //源点到各点的最短距离
memset(vis,0,sizeof(vis)); //是否访问过该点
d[s]=0;
priority_queue<node> q;
q.push((node){s,d[s]}); //放入优先队列
while(!q.empty()){ //只要队列不为空,就取出源点到某点最短距离的顶点
node temp=q.top();
q.pop();
int u = temp.st;
if(vis[u]) continue; //如果已经访问过了就没必要更新
vis[u]=1;
for(int j=0;j<edge[u].size();j++){ //u的所有邻边
node t = edge[u][j];
int v= t.st;
int value = t.len;
if(d[v] > d[u] + value){
d[v]=d[u] + value;
q.push((node){v,d[v]});
}
}
}
}
int main(){
int u,v,w,n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
cin>>u>>v>>w;
edge[u].push_back((node){v,w});
edge[v].push_back((node){u,w});
}
Dijkstra(0,n);
for(int i=0;i<n;i++){
printf("%d ",d[i]);
}
return 0;
}
SPFA算法
期望时间复杂度为O(kE),其中E是图的边数,k是一个常数,在很多情况下k不超过2
经常性地由于堆优化的Dijkstra算法
#include<iostream>
#include<cstdio>
#include<queue>
#include<vector>
#include<cstring>
#include<algorithm>
using namespace std;
const int maxn=110,INF=1e9;
int inq[maxn],d[maxn],num[maxn];
struct node{
int v,dist;
node(int _v, int _dist):v(_v),dist(_dist){}
};
vector<node> A[maxn];
void SPFA(int s){
memset(inq,0,sizeof(inq));
memset(num,0,sizeof(num));
fill(d,d+maxn,INF);
queue<int> q; //队列存的是整数
q.push(s);
inq[s]=1; //s入队了标记为1
num[s]++; //入队次数加一
d[s]=0; //起点的最短路径为0
while(!q.empty()){
int u=q.front(); //取出队首的元素
q.pop();
inq[u]=0; //标记为不在队列中
for(int j=0;j<A[u].size();j++){
int v = A[u][j].v;
int dist = A[u][j].dist;
if(d[v] > d[u] + dist){
d[v] = d[u] + dist;
if(!inq[v]){ //如果v不在队列中,则入队
q.push(v);
inq[v]=1;
num[v]++;
//if(num[v]>=n) return false;
}
}
}
}
//return true;
}
int main(){
int u,v,w,n,m;
scanf("%d%d",&n,&m);
for(int i=0;i<m;i++){
cin>>u>>v>>w;
A[u].push_back(node(v,w));
A[v].push_back(node(v,w));
}
SPFA(0);
for(int i=0;i<n;i++){
printf("%d ",d[i]);
}
return 0;
}
测试数据
输入:
5 6
0 1 1
0 2 2
0 3 1
1 2 1
2 4 1
3 4 1
输出:
0 1 2 1 2
Bellman-Ford算法
用于处理含有负权的图
主要思路:
1.对图中的边进行V-1***作
2.每轮都遍历图中所有的边,判断是否能更新为更小
时间复杂度O(VE)
V为顶点数,E为边数
SPFA是Bellman-Ford算法的改进