信息学奥赛一本通 1382:最短路(Spfa)

【题目链接】

ybt 1382:最短路(Spfa)

【题目考点】

1. 图论 单源最短路径

图中有V个顶点E条边,单源最短路径算法时间复杂度:

  • 朴素Dijkstra算法: O ( V 2 ) O(V^2) O(V2)
  • Dijkstra堆优化算法: O ( E l o g E ) O(ElogE) O(ElogE)
  • SPFA算法:一般情况下 O ( k E ) O(kE) O(kE),k为顶点平均入队次数,最坏情况下 O ( V E ) O(VE) O(VE)
    空间复杂度:
  • 邻接矩阵: O ( V 2 ) O(V^2) O(V2)
  • 邻接表: O ( V + E ) O(V+E) O(V+E)

【解题思路】

该题顶点数量为100000,存储结构只能用邻接表。
如果用朴素Dijkstra算法, O ( V 2 ) O(V^2) O(V2)复杂度, V 2 V^2 V2会达到 1 0 10 10^{10} 1010,超过了 1 0 7 10^7 107,是不可接受的。所以不能用朴素Dijkstra算法。
对于复杂度为 O ( E l o g E ) O(ElogE) O(ElogE)的Dijkstra堆优化算法,是可以使用的。
边数 5 ∗ 1 0 5 5*10^5 5105相比于 V 2 = 1 0 10 V^2 = 10^{10} V2=1010是很小的,可以认为题目中给定的图都是稀疏图,k会比较小,可以使用SPFA算法。
【注意】:题目中说可能有重边和自环,这两点并不会影响Dijkstra算法和SPFA算法的运行,有重边就添加到邻接表中即可,不用特意排除重边。
【注】:邻接表的链式前向星写法相较于vector数组写法更麻烦一些,所以如无特殊说明,本人题解中默认都使用vector数组写法。要改为链式前向星写法也很容易,因而不再赘述链式前向星写法的题解。

【题解代码】

解法1:SPFA算法+邻接表
#include<bits/stdc++.h>
using namespace std;
#define N 100005
struct Edge
{
	int t, w; 
	Edge(){}
	Edge(int a, int b):t(a),w(b){}
};
vector<Edge> edge[N];
bool vis[N];//vis[i]:顶点i是否在队列中 
int n, m, dis[N];//dis[i]:当前情况下v0到i的最短路径距离
void initGraph()
{
	int f, t, w;
    cin >> n >> m;
    for(int i = 1; i <= m; ++i)
    {
    	cin >> f >> t >> w;//从f到t权值w 
    	edge[f].push_back(Edge(t, w));
    	edge[t].push_back(Edge(f, w));
	}
}
void spfa(int sv)//sv起始点 
{
	memset(dis, 0x3f, sizeof(dis));//dis初始值为INF
	queue<int> que;
	dis[sv] = 0; 
	vis[sv] = true;
    que.push(sv);
	while(que.empty() == false)
    {
        int u = que.front();
        que.pop();
        vis[u] = false;
        for(int i = 0; i < edge[u].size(); ++i)
        {
            int v = edge[u][i].t, w = edge[u][i].w;
            if(dis[v] > dis[u] + w)
            { 
                dis[v] = dis[u] + w;
                if(vis[v] == false)
                {
                    vis[v] = true;
                    que.push(v);
                }
            }
        }
    }
}
int main()
{
	initGraph();
	spfa(1);
	cout << dis[n];
    return 0;
}
解法2:Dijkstra堆优化算法+邻接表
#include<bits/stdc++.h>
using namespace std;
#define N 100005
struct Pair
{
    int u, d;//u:顶点 d:距离 
    Pair(){}
    Pair(int a, int b):u(a),d(b){}
    bool operator < (const Pair &b) const
    {
        return b.d < d;
    }
};
struct Edge
{
	int t, w; 
	Edge(){}
	Edge(int a, int b):t(a),w(b){}
};
vector<Edge> edge[N];
bool vis[N];//vis[i]表示从v0到i点的最短路径是否已经确定  
int n, m, dis[N];//v0:源点 dis[i]:当前情况下v0到i的最短路径距离
void initGraph()
{
	int f, t, w;
    cin >> n >> m;
    for(int i = 1; i <= m; ++i)
    {
    	cin >> f >> t >> w;//从f到t权值w 
    	edge[f].push_back(Edge(t, w));
    	edge[t].push_back(Edge(f, w));
	}
}
void dijkstra(int sv)//sv起始点 
{
    priority_queue<Pair> pq;
	memset(dis, 0x3f, sizeof(dis));//dis初始值为INF
	dis[sv] = 0;
	pq.push(Pair(sv, 0));
	while(pq.empty() == false)
	{
	    int u = pq.top().u;
	    pq.pop();
	    if(vis[u])//如果顶点u已经访问过,则跳过 
	       continue;
	    vis[u] = true;
	    for(int i = 0; i < edge[u].size(); ++i) 
		{
		    int v = edge[u][i].t, w = edge[u][i].w; 
			if(vis[v] == false && dis[v] > dis[u] + w)//松弛
			{
				dis[v] = dis[u] + w;
			    pq.push(Pair(v, dis[v]));
            }
		}
    }
}
int main()
{
	initGraph();
	dijkstra(1);
	cout << dis[n];
    return 0;
}
  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值