【图论】最短路算法 spfa&dijkstra+配对堆优化 hdu1874

目录

1.spfa(Shortest Path Faster Algorithm):

 2.dijkstra+配对堆优化:


 

1.spfa(Shortest Path Faster Algorithm):

可以处理负边但不能处理负环,时间复杂度为O(kN)k为所有顶点进入队列的平均数,N为顶点个数。

算法思想:源点为s,s到i的当前最短路径为d[i],初始时,s到每个点的d[i]都为无穷大,d[s]为0.算法过程中不断减小d[i],最终将其中的每个元素减小为实际的最短路。

我们需要维护一个队列,首先将源点入队列,扫描它可以直接走到的节点,对它们进行松弛操作,并且将这些节点入队列,如果已经在队列里了,那就不需要再入队列,我们用一个inq数组来标记某个节点是否在队列里。

 

松弛操作:原理就是“三角形两边之和大于第三边”,判断d[j]>d[i]+w[i,j],若成立那么将d[j]更新为d[i]+w[i,j],否则不动。

hdu1874 ac代码:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 205;
vector<pair<int, int> >E[maxn];
int n, m;
int d[maxn], inq[maxn];

void init()
{
	for (int i = 0;i < maxn;i++)E[i].clear();
	for (int i = 0;i < maxn;i++)inq[i] = 0;
	for (int i = 0;i < maxn;i++)d[i] = 1e9;
}
int main()
{
	while (cin >> n >> m)
	{
		init();
		for (int i = 0;i < m;i++)
		{
			int x, y, z;scanf("%d%d%d", &x, &y, &z);
			E[x].push_back(make_pair(y, z));
			E[y].push_back(make_pair(x, z));
		}
		int s, t;
		scanf("%d%d", &s, &t);
		queue<int>Q;
		Q.push(s);
		d[s] = 0;inq[s] = 1;
		while (!Q.empty())
		{
			int now = Q.front();
			Q.pop();
			inq[now] = 0;
			for (int i = 0;i < E[now].size();i++)
			{
				int v = E[now][i].first;
				if (d[v] > d[now] + E[now][i].second)
				{
					d[v] = d[now] + E[now][i].second;
					if (!inq[v])
					{
						inq[v] = 1;
						Q.push(v);
					}
				}
			}
		}
		if (d[t] == 1e9)
			printf("-1\n");
		else
			printf("%d\n", d[t]);
	}
	return 0;
}

 2.dijkstra+配对堆优化:

适用于边权为正的图(有向图或无向图) 不适用于处理有负边的图。

算法思想:

1.初始时将源点看成集合s,其他的点为另一个集合,与源点相连的点d[i]为边权值,其他的点为无穷大。

2.取最小的d[i](这里用到的是优先队列),并将它连着的点加入集合s

3.对与他连着的这个点相邻的节点松弛操作

4.重复2.3直到终点进入集合s

代码如下:

#include<iostream>
#include<cstdio>
#include<vector>
#include<queue>
using namespace std;
const int maxn = 205;
vector<pair<int, int> >E[maxn];
int n, m;
int d[maxn];

void init()
{
	for (int i = 0;i < maxn;i++)E[i].clear();
	for (int i = 0;i < maxn;i++)d[i] = 1e9;
}
int main()
{
	while (cin >> n >> m)
	{
		init();
		for (int i = 0;i < m;i++)
		{
			int x, y, z;scanf("%d%d%d", &x, &y, &z);
			E[x].push_back(make_pair(y, z));
			E[y].push_back(make_pair(x, z));
		}
		int s, t;
		scanf("%d%d", &s, &t);
		priority_queue<pair<int,int > >Q;
		d[s] = 0;
		Q.push(make_pair(-d[s], s));
		while (!Q.empty())
		{
			int now = Q.top().second;
			Q.pop();
			for (int i = 0;i < E[now].size();i++)
			{
				int v = E[now][i].first;
				if (d[v] > d[now] + E[now][i].second)
				{
					d[v] = d[now] + E[now][i].second;
					Q.push(make_pair(-d[v],v));
				}
			}
		}
		if (d[t] == 1e9)
			printf("-1\n");
		else
			printf("%d\n", d[t]);
	}
	return 0;
}

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值