图最短路径

1.单源最短路径

1.Bellman-ford(可以判断负环 处理负权)

void bellman(int cur) {
    
    
	for (int i = 1; i <= n; i++) dis[i] = INF;
	dis[1] = 0;
	for (int i = 0; i < m; i++)
	{
    
    
		memcpy(backup, dis, sizeof dis);
		for (int j = 0; j < edge.size(); j++)
		{
    
    
			int a = edge[j].first, b = edge[j].second, c = 1;
			dis[b] = min(dis[b], backup[a] + c);
		}
	}
}

2.spfa(可以判断负环 处理负权)

void spfa(int cur){
    
    
	for (int i = 0; i <= n; i++){
    
     dis[i] = INF; vis[i] = 0; }
	dis[cur] = 0;
	queue<int> q;
	q.push(cur);
	while (!q.empty()){
    
    
		int top = q.front(); q.pop();
		vis[top] = 0;
		for (auto &point : e[top]){
    
    
			int nx = point.first, v = point.second;
			if (dis[nx] > dis[top] + v){
    
    
				dis[nx] = dis[top] + v;
				if (!vis[nx]){
    
    
					vis[nx] = 1;
					q.push(nx);
				}
			}
		}
	}
}

3.dijkstra算法(只能处理正权)

void dijkstra(int cur){
    
    
	for (int i = 0; i <= n; i++){
    
     dis[i] = INF; vis[i] = 0; }
	dis[cur] = 0;
	priority_queue<PII, vector<PII>, greater<PII>> q;
	q.push({
    
    0,cur});

	while (!q.empty()){
    
    
		int top = q.top().second; q.pop();
		if (vis[top])continue;
		vis[top] = 1;
		for (auto &point : e[top]){
    
    
			int nx = point.first, v = point.second;
			if (!vis[nx] && dis[nx] > dis[top] + v){
    
    
				dis[nx] = dis[top] + v;
				q.push({
    
    dis[nx],nx});
			}
		}
	}
}

2.多源最短路径
1.Floyd (处理负权)

void floyd() {
    
    
	for (int k = 1; k <= n; k++) {
    
    
		for (int i = 1; i <= n; i++) {
    
    
			for (int j = 1; j <= n; j++) {
    
    
				dis[i][j] = min(dis[i][j], dis[i][k] + dis[k][j]);
			}
		}
	}
}

2.Johnson
Johnson 算法则通过一种方法来给每条边重新标注边权。
我们新建一个虚拟节点(在这里我们就设它的编号为 0)。从这个点向其他所有点连一条边权为 0 的边。
接下来用 Bellman-Ford 算法求出从 0 号点到其他所有点的最短路,记为 h i h_i hi

假如存在一条从 u 点到 v 点,边权为 w 的边,则我们将该边的边权重新设置为 w + h u − h v w + h_u - h_v w+huhv
接下来以每个点为起点,跑 n 轮 Dijkstra 算法即可求出任意两点间的最短路了。

那这么说,Dijkstra 也可以求出负权图(无负环)的单源最短路径了?

对于任意一点 ( u , v ) (u,v) (u,v), 根据三角不等式, h v < h u + w ( u , v ) h_v < h_u + w(u,v) hv<hu+w(u,v)
w ′ ( u , v ) = w ( u , v ) + h u − h v ≥ 0 w^{'}(u,v)=w(u,v) + h_u - h_v \geq 0 w(u,v)=w(u,v)+huhv0

P5905 【模板】Johnson 全源最短路

#include <iostream>
#include <istream>
#include <sstream>
#include <vector>
#include <stack>
#include <list>
#include <map>
#include <set>
#include <deque>
#include <queue>
#include <cstring>
#include <unordered_map>
#include <unordered_set>
#include <algorithm>
#include <numeric>
#include <chrono>
#include <ctime>
#include <cmath>
#include <cctype>
#include <string>
#include <cstdio>
#include <iomanip>


#include <thread>
#include <mutex>
#include <condition_variable>
#include <functional>
#include <iterator>
using namespace std;

//void rfIO()
//{
    
    
//	FILE *stream1;
//	freopen_s(&stream1,"in.txt", "r", stdin);
//	freopen_s(&stream1,"out.txt", "w", stdout);
//}

inline void read(int &x){
    
    
	x = 0;
	char ch = getchar(); int f = 1;
	while (!isdigit(ch) && ch^'-') ch = getchar();
	if (ch == '-') f = -1, ch = getchar();
	while (isdigit(ch)) x = x * 10 + ch - '0', ch = getchar();
	x *= f;
}
static auto speedup = [](){
    
    ios::sync_with_stdio(false); cin.tie(); cout.tie(); return nullptr; }();

typedef long long int ll;
typedef pair<int, ll> PII;
const int maxn = 3e3 + 7,INF = 1e9;
ll n, m,vis[maxn],tcnt[maxn],dis[maxn],d[maxn];
vector<PII> matrix[maxn];

bool spfa(int s){
    
    
	for (int i = 1; i <= n; i++)d[i] = INF, vis[i] = 0;
	d[s] = 0; vis[s] = 1;
	queue<int> q;
	q.push(s);
	while (!q.empty()){
    
    
		int top = q.front();
		q.pop();
		vis[top] = 0;
		for (int i = 0; i < matrix[top].size(); i++){
    
    
			PII pi = matrix[top][i];
			int nx = pi.first, w = pi.second;
			if (d[nx] > d[top] + w){
    
    
				if (!vis[nx]){
    
    
					if (++tcnt[nx] >= n + 1) return false;
					d[nx] = d[top] + w;
					q.push(nx);
					vis[nx];
				}
			}
		}
	}
	return true;
}

void dijkstra(int s){
    
    
	for (int i = 1; i <= n; i++)dis[i] = INF;
	memset(vis, 0, sizeof(vis));
	dis[s] = 0;
	priority_queue<PII, vector<PII>, greater<PII>> q;
	q.push({
    
     0, s });
	while (!q.empty()){
    
    
		int top = q.top().second; q.pop();
		if (vis[top])continue;
		vis[top] = 1;
		for (int i = 0; i < matrix[top].size(); i++){
    
    
			PII pi = matrix[top][i];
			int nx = pi.first, w = pi.second;
			if (dis[nx] > dis[top] + w){
    
    
				dis[nx] = dis[top] + w;
				q.push({
    
     dis[top] + w,nx });
			}
		}
	}
}
int main()
{
    
    
	int x, y, z;
	cin >> n >> m;
	for (int i = 1; i <= m; i++){
    
    
		cin >> x >> y >> z;
		matrix[x].push_back({
    
     y, z });
	}
	for (int i = 1; i <= n; i++){
    
    
		matrix[n + 1].push_back({
    
    i,0});
	}
	if (!spfa(n + 1)){
    
    
		cout << -1 << endl;
		return 0;
	}
	for (int i = 1; i <= n; i++){
    
    
		for (int j = 0; j < matrix[i].size(); j++){
    
    
			int a = i, b = matrix[i][j].first,w = matrix[i][j].second;
			matrix[i][j].second += d[a] - d[b];
		}
	}
	for (int i = 1; i <= n; i++){
    
    
		dijkstra(i);
		long long ans = 0;
		for (int j = 1; j <= n; j++)
		{
    
    
			if (dis[j] == INF) ans += 1ll * j*INF;
			else ans += 1ll * j*(dis[j] + (d[j] - d[i]));
			
		}
		printf("%lld\n", ans);
	}
	return 0;
}

猜你喜欢

转载自blog.csdn.net/seanbill/article/details/130553320