最短路总结:Dijkstra,SFPA,Bellman Ford判负环,Floyd

Dijkstra:(只能处理非负的)

贪心思想:

1、找到最短距离已经确定的顶点,从它出发更新相邻顶点的最短距离。

2、此后不需要再关心1中的“最短距离已确定的顶点”。

优先队列优化:

在队列中取出d值最小的结点x,然后从x出发更新所有的边的d值。

初始化:

first[u]  结点u的第一条边

next[i] 边i的下一条边

d -> INF

时间复杂度O(elogv)

《最短路总结:Dijkstra,SFPA,Bellman Ford判负环,Floyd》

#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;
//距离,边序号 
typedef pair<int ,int> P;
priority_queue<P, vector<P>, greater<P> >que;
const int MAX_N = 10000, MAX_M = 10000;
int d[MAX_N];
struct E
{
	int u, v, w;
}e[MAX_M];
int first[MAX_N], next[MAX_M];
void Dijkstra(int s)
{
	//初始化,距离数组d,队列 
	memset(d, 0x3f, sizeof(d));
	d[s] = 0;
	que.push(P(d[s], s));
	while(que.size())
	{
		P x = que.top(); que.pop();	//取出
		int u = x.second;
		if(x.first != d[u])			//已经算过了,跳过 
			continue;  
		for(int i = first[u]; i != -1; i = next[i])
			if(d[u] + e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[u] + e[i].w;
				que.push(P(d[e[i].v], e[i].v));
			}
	}
}

int main(int argc, char *argv[])
{
	memset(first, -1, sizeof(first));
	int n, m;
	scanf("%d%d", &n, &m);
	for(int i = 0; i < m; i++)
	{
		scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
		next[i] = first[e[i].u];
		first[e[i].u] = i;
	}
	Dijkstra(e[0].u);
	printf("%d\n", d[5]);
	return 0;
}

SPFA算法 负环最短路(用队列优化对Bellman Ford算法的优化):

时间复杂度:O(ke)。

初始化:

first[u]  结点u的第一条边

next[i] 边i的下一条边

d -> INF

《最短路总结:Dijkstra,SFPA,Bellman Ford判负环,Floyd》

bool inq[MAX_N];
void SPFA(int s)
{
	//初始化距离d,队列,inq队列标志 
	queue<int> que;
	memset(d, 0x3f, sizeof(d));
	d[s] = 0;
	memset(inq, 0, sizeof(inq));
	que.push(s);
	while(que.size())
	{
		int u = que.front();	que.pop();
		//清除标志 
		inq[u] = false;			
		//对每一条邻边松弛操作 
		for(int i = first[u]; i != -1; i = next[i])		 
			if(d[e[i].u] + e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[e[i].u] + e[i].w;
				if(!inq[e[i].v])
				{
					inq[e[i].v] = true;
					que.push(e[i].v);
				}
			}
	}
}

Bellman Ford算法判断是否存在负环:

若循环执行了n-1次,则存在负环。

注:d初始化为0即可

《最短路总结:Dijkstra,SFPA,Bellman Ford判负环,Floyd》

bool find_negative_loop()
{
	memset(d, 0, sizeof(d));
	for(int i = 0; i < n; i++)
		for(int j = 0; j < m; j++)
		{
			int u = e[j].u, v = e[j].v, w = e[j].w;
			if(d[u] + w < d[v])
			{
				d[v] = d[u] + w;
				if(i == n-1)
				return true;
			}
		}
	return false;
} 

Floyd-Warshall任意两点最短路算法:

动态规划的思想:

d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

时间复杂度O(v^3)。

初始化:

d[][] -> INF

d[i][i] = 0;

d[u][v] = w;

《最短路总结:Dijkstra,SFPA,Bellman Ford判负环,Floyd》

void Floyd()
{
	for(int k = 0; k < n; k++)
		for(int i = 0; i < n; i++)
			for(int j = 0; j < n; j++)
				d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
}

测试:

#include <iostream>
#include <cstring>
#include <queue>
#include <vector>
#include <functional>
using namespace std;

int n, m;
//dist, u
typedef pair<int, int> P;
priority_queue<P, vector<P>, greater<P> >que;  
const int MAX_N = 10000, MAX_M = 10000;
int d[MAX_N];	//distant

struct E
{
	int u, v, w;
}e[MAX_M];

int first[MAX_N], nexte[MAX_M];

void Dijkstra(int s)
{
	memset(d, 0x3f, sizeof(d));
	d[s] = 0;
	que.push(P(d[s], s));  
	while(que.size())
	{
		P x = que.top(); que.pop();
		int u = x.second;		//u
		if(x.first != d[u])		//calc~ed
			continue;
		for(int i = first[u]; i != -1; i = nexte[i])
			if(d[u] + e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[u] + e[i].w;
				que.push(P(d[e[i].v], e[i].v));
			}
	}
}

bool inq[MAX_N];
void SPFA(int s)
{
	//init
	queue<int> que;
	memset(d, 0x3f, sizeof(d));
	d[s] = 0;
	memset(inq, 0, sizeof(inq));

	que.push(s);
	while(que.size())
	{
		int u = que.front(); que.pop();
		//clear flag
		inq[u] = false;
		//relax
		for(int i = first[u]; i != -1; i = nexte[i])
			if(d[e[i].u] + e[i].w < d[e[i].v])
			{
				d[e[i].v] = d[e[i].u] + e[i].w;
				if(!inq[e[i].v])
				{
					inq[e[i].v] = true;
					que.push(e[i].v);
				}
			}
	}
}

int dist[MAX_N][MAX_N];
void Floyd()
{
	for(int k = 0; k < n; k++)
		for(int i = 0; i < n; i++)
			for(int j = 0; j < n; j++)
				dist[i][j] = min(dist[i][j], dist[i][k] + dist[k][j]);
}

int main()
{
	freopen("in.txt", "r", stdin);
	memset(first, -1, sizeof(first));

	//Floyd
	memset(dist, 0x3f, sizeof(dist));
	for(int i = 0; i < n; i++)	dist[i][i] = 0;

	scanf("%d%d", &n, &m);
	for(int i = 0; i < m; i++)
	{
		scanf("%d%d%d", &e[i].u, &e[i].v, &e[i].w);
		nexte[i] = first[e[i].u];
		first[e[i].u] = i;

		//Floyd
		dist[e[i].u][e[i].v] = e[i].w;
	}
	Dijkstra(e[0].u);
	printf("%d to %d dist = %d\n", e[0].u, n-1, d[n-1]);

	SPFA(e[0].u);
	printf("%d to %d dist = %d\n", e[0].u, n-1, d[n-1]);

	Floyd();
	printf("%d to %d dist = %d\n", e[0].u, n-1, dist[e[0].u][n-1]);

	for(int i = 0; i < n; i++)
		for(int j = 0; j < n; j++)
		{
			if(dist[i][j] == 0x3f3f3f3f)
				printf("INF");
			else
				printf("%3d", dist[i][j]);
			printf(j == n-1 ? "\n" : " ");
		}

	return 0;
}

/************************************************************************/
/* 
input:
6 8  
0 2 10  
0 4 30  
0 5 100  
1 2 5  
2 3 50  
3 5 10  
4 3 20  
4 5 60                                                                       */
/************************************************************************/
    原文作者:Bellman - ford算法
    原文地址: https://blog.csdn.net/nw4869/article/details/21718413
    本文转自网络文章,转载此文章仅为分享知识,如有侵权,请联系博主进行删除。
点赞