SPFA、迪杰斯特拉、弗洛伊德算法C++实现

三者不同,就我个人理解而言,迪杰斯特拉是求单源点最短路径且权值为非负,算法效率为O(nlogn):;弗洛伊德算法是求任意两点间的最短路径,算法复杂度高,为O(n^3);SPFA为单源点最短路径,权值可为负数,时间复杂度为O(nm);三者均可以处理有向和无向图。

且我觉得你只要会了SPFA,另外两种都可以解决,SPFA既可以求负值也可以求解正的权值,再多加一层for循环那么弗洛伊德求任意亮点最短路径也可以解决。

1.SPFA

第一种写法:vector+结构体

#include <bits/stdc++.h>
using namespace std;
const int INF = 0x3f3f3f3f;

struct node{
	int v,weight;
};
vector<node> V[MAX];  //二维动态数组
int vis[MAX],dis[MAX];  //dis[i]用以存储源点dao点i的最短路径 vis[i]为点i是否在队列中 
void SPFA(int src){
	queue<node> q;
	q.push_back(src);
	vis[src]=1;
	dis[src]=0;
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		vis[t]=0;
		for(int i=0;i<V[t].size();i++)
		{
			if(dis[t]+V[t][i].weight<dis[V[t][i].v])
			{
				dis[V[t][i].v]=dis[t]+V[t][i].weight;
				if(!vis[V[t][i].v])
				{
					vis[V[t][i].v]=1;
					q.push_back(V[t][i].v);
				}
			}
		 } 
	}
}

int main() {
	int n,s,t;  //分别表示n个节点,s为源点,t为终点
	memset(dis,INF,sizeof dis);
	for(int i=0;i<n;i++)
	{
		int u,v,w;
		cin>>u>>v>>w;
		node t;
		t.v=v;
		t.weight=w;
		V[u].push_back(t);
		t.v=u;
		V[u].push_back(t);  //两个同时push表明为无向图 若有向图只push一个值即可 
	}
	SPFA(s);
	cout<<dis[t];
	return 0;
}

第二种写法:vector+pair,基本差不多,看起来会简洁一些

#include<bits/stdc++.h>
using namespace std;

const int MAX = 1e5+10;
const int INF=0x3f3f3f3f;
typedef pair<int,int> PII;

vector<PII> V[MAX];
int d[MAX],vis[MAX];

void SPFA(int src)
{
	memset(d,INF,sizeof d);
	queue<int> q;
	q.push(src);
	vis[src]=1;
	d[src]=0;
	
	while(!q.empty())
	{
		int t=q.front();
		q.pop();
		vis[t]=0;
		for(auto k:V[t])
		{
			if(d[t]+k.second<d[k.first])
			{
				d[k.first]=d[t]+k.second;
				if(!vis[k.first])
				{
					vis[k.first]=1;
					q.push(k.first);
				}
			}
		}
	}
	
}

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		V[u].push_back({v,w});
	}
	
	SPFA(1);
	if(d[n]==INF)
		cout<<-1;
	else
		cout<<d[n];
 } 

2.Dijkstra

vector+堆优化

#include<bits/stdc++.h>
using namespace std;

const int MAX = 1e5+10;
const int INF=0x3f3f3f3f;
typedef pair<int,int> PII;

vector<PII> V[MAX];
int d[MAX],vis[MAX];

void Dijkstra()
{
	memset(d,INF,sizeof d);
	priority_queue<PII,vector<PII>,greater<PII>> q;
	q.push({0,1});
	d[1]=0;
	
	while(!q.empty())
	{
		PII t=q.top();
		q.pop();
		int ver=t.second;
		for(auto k:V[ver])
		{
			int j=k.first,w=k.second;
			if(d[ver]+w<d[j])
			{
				d[j]=d[ver]+w;
				q.push({d[j],j});
			}
				
		}
	}
	
}

int main()
{
	int n,m;
	cin>>n>>m;
	for(int i=0;i<m;i++)
	{
		int u,v,w;
		scanf("%d%d%d",&u,&v,&w);
		V[u].push_back({v,w});
	}
	
	Dijkstra();
	if(d[n]==INF)
		cout<<-1;
	else
		cout<<d[n];
 } 

3.弗洛伊德

DP可以解决,复杂度较高

#include <bitsdc++.h>
using namespace std;

const int N = 210, INF = 0x3f3f3f3f;

int d[N][N];
int n, m, k;

int main() {
    
    scanf("%d%d%d", &n, &m, &k);
    
    memset(d, 0x3f, sizeof d);
    for(int i=1; i<=n; i++) d[i][i] = 0;
    
    for(int i=0; i<m; i++) {
        int a, b, c;
        scanf("%d%d%d", &a, &b, &c);
        d[a][b] = min(d[a][b], c);
    }
    
    for(int k=1; k<=n; k++) {
        for(int i=1; i<=n; i++) {
            for(int j=1; j<=n; j++) {
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            }
        }
    }
    
    while(k--) {
        int a, b;
        scanf("%d%d", &a, &b);
        if(d[a][b] >= INF/2) cout << "impossible" << endl;
        else cout << d[a][b] << endl;
    }
    
    
    return 0; 
}

  • 0
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值