Loading

最短路算法

Floyd

纯暴力,三个 for 循环

复杂度: \(O(V^3)\)

for(int k = 1;k <= n;k++){
	for(int i = 1;i <= n;i++){
		for(int j = 1;j <= n;j++){
			if(dis[i][k] + dis[k][j] < dis[i][j]){
				//...
			}
		}
	}
}

Bellman-Ford

用边去进行松弛操作,可以判环

复杂度: \(O(VE)\)

#include<bits/stdc++.h>
using namespace std;

const int maxm = 2e5 + 10;
const int maxn = 1e5 + 10;

struct E {
	int from, to, w;
}Edges[maxm];

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

bool bellman_ford(int s) {

	for (int i = 1; i < n; i++) {//松弛n-1次
		for (int j = 0; j < m; j++) {
			int f = Edges[j].from, t = Edges[j].to, w = Edges[j].w;
			if (dis[t] > dis[f] + w) {
				dis[t] = dis[f] + w;
			}
		}
	}

	for (int j = 0; j < m; j++) {
		int f = Edges[j].from, t = Edges[j].to, w = Edges[j].w;
		if (dis[t] > dis[f] + w) {
			return false;//负环
		}
	}
	return true;
}
int main() {
	scanf("%d %d %d", &n, &m, &s);
	memset(dis, 0x3f, sizeof dis);
	dis[s] = 0;//注意dis的初始化
	for (int i = 0; i < m; i++) {
		scanf("%d%d%d", &Edges[i].from, &Edges[i].to, &Edges[i].w);
		if (Edges[i].from == s) {
			dis[Edges[i].to] = Edges[i].w;//初始化
		}
	}
	bellman_ford(s);
	for (int i = 1; i <= n; i++) {
		printf("%d%s", dis[i], i == n ? "\n" : " ");
        //printf("%d%c",dis[i]," \n"[i==n]);
	}
}

Dijkstra

复杂度\(O(VlogV+E)\)

struct Node {
	long long d;
	int u;
	bool operator < (const Node& rhs)const { 
        //rhs,right-hand-side
		return d > rhs.d;
	}
};

void dijkstra(int s) {
	priority_queue<Node>Q;
	for (int i = 1;i <= n;i++) {
		d[i] = INF;
	}
	d[s] = 0;

	memset(vis, 0, sizeof(vis));
	Q.push(Node{ 0,s });
	
	while (!Q.empty()) {
		Node x = Q.top();Q.pop();

		int u = x.u;

		if (vis[u]) {
			continue;
		}

		vis[u] = 1;

		for (int i = 0;i < G[u].size();i++) {
			Edge e = edges[G[u][i]];
			if (d[e.to] > d[u] + e.dist) {
				d[e.to] = d[u] + e.dist;
				p[e.to] = G[u][i];
				Q.push(Node{ d[e.to],e.to });
			}
		}
	}
}

SPFA

\(O(kE)\)\(k\) 为每个节点入队次数

最坏 \(O(EV)\)

#include<bits/stdc++.h>
using namespace std;

const int maxn = 1e6 + 10;
struct Edge {
	int to, w, next;
}E[maxn];

int head[maxn], tot;

void AddEdge(int from, int to, int w) {
	E[tot] = Edge{ to,w,head[from] };
	head[from] = tot++;
}

int n, m, s;
const int inf = 0x3f3f3f3f;// inf > (1e9)
int dis[maxn], vis[maxn];

void spfa() {
	queue<int> q;
	memset(dis, 0x3f, sizeof(int) * (n + 10));
	memset(vis, 0, sizeof(int) * (n + 10));

	q.push(s); dis[s] = 0; vis[s] = 1; //第一个顶点入队,进行标记
	while (!q.empty()) {
		int u = q.front();
		q.pop(); vis[u] = 0;
		for (int i = head[u]; ~i; i = E[i].next) {
			int v = E[i].to;
			if (dis[v] > dis[u] + E[i].w) {
				dis[v] = dis[u] + E[i].w;
				if (vis[v] == 0) {
                    //此处判环
                    //if(++cnt[v] >= n) 有负环
					vis[v] = 1;
					q.push(v);
				}
			}
		}
	}
}

int main() {

	scanf("%d%d%d", &n, &m, &s);
	memset(head, 0xff, sizeof(int) * (n + 10));
	tot = 0;
	for (int i = 0; i < m; i++) {
		int a, b, w;
		scanf("%d%d%d", &a, &b, &w);
		AddEdge(a, b, w);
	}
	spfa();
	for (int i = 1; i <= n; i++) {
		printf("%d%c", dis[i] == 0x3f3f3f3f ? (1 << 31) - 1 : dis[i], " \n"[i == n]);
	}
}
posted @ 2020-09-11 14:07  —O0oO-  阅读(117)  评论(0编辑  收藏  举报