最短路

写于 CSP 前一天,复习最短路。

单源最短路

bellman-ford

每次全图进行松弛,可以证明执行 n n n 次后可以找到最短路。时间复杂度 O ( n m ) O(nm) O(nm)

// bellman-ford

#include 
#define int long long
using namespace std;

const int N = 1e5 + 5;

struct Edge{
	int to, w;
};

vector <Edge> G[N]; 

int n, m, s, dis[N];

signed main()
{
	cin >> n >> m >> s;
	
	for(int i=1; i<=n; i++)
		dis[i] = INT_MAX;
	
	// s 为起点 
	dis[s] = 0; 
	
	for(int i=1; i<=m; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		G[u].push_back({v, w});
	}
	
	for(int i=1; i<=n; i++)
	{
		for(int u=1; u<=n; u++)
		for(Edge i : G[u])
		{
			int v = i.to, w = i.w;
			if(dis[v] > dis[u] + w)
				dis[v] = dis[u] + w;
		}
	}
	
	for(int i=1; i<=n; i++)
		cout << dis[i] << " ";
}


spfa

bellman-ford 每次对全图松弛有些多余,显然对于每一轮,只有上一轮进行松弛的点在本轮才能进行松弛。用队列存需要松弛的点。

// spfa

#include 
#define int long long
using namespace std;

const int N = 1e5 + 5;

struct Edge{
	int to, w;
};

vector <Edge> G[N];

int n, m, s, dis[N];

bool flag[N];

signed main()
{
	cin >> n >> m >> s;
	
	for(int i=1; i<=n; i++)
		dis[i] = INT_MAX;
	
	dis[s] = 0;
	
	for(int i=1; i<=m; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		G[u].push_back({v, w});
	}
	
	queue <int> q; q.push(s);
	
	while(!q.empty())
	{
		int u = q.front(); q.pop();
		
		if(flag[u]) continue;

		flag[u] = 1;
		
		for(Edge i : G[u])
		{
			int v = i.to, w = i.w;
			if(dis[v] > dis[u] + w)
			{
				dis[v] = dis[u] + w;
				q.push(v);
			}
		}
		
		flag[u] = 0;
	}
	
	for(int i=1; i<=n; i++)
		cout << dis[i] << " ";
}

dijisktra

要求:边权非负。

过程:两个集合 S , T S, T S,T 分别表示已确定最短路及未确定最短路的点集,初始时所有点都在 T T T 中, d i s ( s ) = 0 dis(s)=0 dis(s)=0,其余点 d i s = ∞ dis = \infin dis=。每次取 T T T d i s dis dis 最小的点将其加入 S S S 中,对其所有出边进行松弛。

可以用堆维护 T T T 中距离最小的点。

证明 ∀ u ∈ T \forall u \in T uT u u u 当前的最短距离均有 S S S 中元素转移记为 D u D_u Du。对于每次取出的 T T T D D D 最小的 u u u,考虑到边权非负且 D u D_u Du 最小,从 T T T 中其他点转移一定不优,故 D u D_u Du 即为最短路。

复杂度:考虑到每个点可能被多次放入堆中,堆内至多 m m m 个元素。时间复杂度 O ( n log ⁡ m + m ) O(n \log m+m) O(nlogm+m)

// dijisktra 

#include 
#define int long long
using namespace std;

const int N = 1e5 + 5;

struct Edge{
	int to, w;
};

vector <Edge> G[N];

int n, m, s, dis[N];

bool flag[N];

struct Node{
	int ver, val;
};

bool operator < (Node x, Node y)
{
	return x.val > y.val;
}

signed main()
{
	cin >> n >> m >> s;
	
	for(int i=1; i<=n; i++)
		dis[i] = INT_MAX;
	
	dis[s] = 0;
	
	for(int i=1; i<=m; i++)
	{
		int u, v, w;
		cin >> u >> v >> w;
		G[u].push_back({v, w});
	}
	
	priority_queue <Node> q;
	
	q.push({s, 0});
	
	while(!q.empty())
	{
		int u = q.top().ver; q.pop();
		
		if(flag[u]) continue;
		
		flag[u] = 1;
		
		for(Edge i : G[u])
		{
			int v = i.to, w = i.w;
			if(dis[v] > dis[u] + w)
			{
				dis[v] = dis[u] + w;
				q.push({v, dis[v]});
			}
		}
	}
	
	for(int i=1; i<=n; i++)
		cout << dis[i] << " ";
}

你可能感兴趣的:(学习笔记,c++)