最短路径算法

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算法的改进

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值