判斷負環模板

Ke_scholar發表於2024-04-28

判斷負環模板

Bellman_ford \(\mathcal{O}(nm)\)

struct Bellman_ford {
	using i64 = long long;
	using PII = pair<i64, i64>;
	int n;
	vector<i64> dis;
	vector<array<int, 3>> edge;
	Bellman_ford(int n): n(n) {
		dis.resize(n + 1, INT_MAX);
	}

	void add(int u, int v, int w) {
		edge.push_back({u, v, w});
	}

	bool ok(int x) {
		dis[x] = 0;
		for (int i = 1 ; i < n; i ++) {
			for (auto [u, v, w] : edge) {
                //從頂點x出發是否能到達的負環
                //若只判斷圖是否存在負環,則去掉上下的if...INT_MAX
				if (dis[u] != INT_MAX)
					dis[v] = min(dis[v], dis[u] + w);
			}
		}
		for (auto [u, v, w] : edge) {
			if (dis[u] == INT_MAX || dis[v] == INT_MAX)
				continue;
			if (dis[v] > dis[u] + w) {
				return true;
			}
		}
		return false;
	}
};

SPFA \(\mathcal{O}(kn)\),最壞\(\mathcal{O}(nm)\)

DFS-SPFA判斷負環很快\(\mathcal{O}(n^2)\),求解慢於BFS-SPFA;

struct SPFA {
	using i64 = long long;
	using PII = pair<i64, i64>;
	vector<i64> dis, cnt;
	vector<bool> vis;
	vector<vector<PII>> g;
	int n;
	SPFA(int n): n(n) {
		dis.resize(n + 1, INT_MAX);
		cnt.resize(n + 1);
		vis.resize(n + 1);
		g.resize(n + 1);
	}

	void add(int u, int v, int w) {
		g[u].push_back({v, w});
	}

	bool ok(int x) {
		queue<int> Q;
		Q.push(x);
		dis[x] = 0, vis[x] = 1;
		while (Q.size()) {
			auto u = Q.front();
			Q.pop();
			vis[u] = 0;
			for (auto [v, w] : g[u]) {
				if (dis[v] > dis[u] + w) {
					dis[v] = dis[u] + w;
					if (!vis[v]) {
						if (++cnt[v] > n)
							return true;
						Q.push(v);
						vis[v] = 1;
					}
				}
			}
		}
		return false;
	}

	bool dfs_spfa(int u) {
		vis[u] = 1;
		for (auto [v, w] : g[u]) {
			if (dis[v] > dis[u] + w) {
				dis[v] = dis[u] + w;
				if (vis[v] || dfs_spfa(v))
					return true;
			}
		}
		vis[u] = 0;
		return false;
	}
};

相關文章