Why does dijkstra relax nodes with have already been processed?

Revision en1, by ayushkoul00, 2022-04-05 16:01:39

When we use a priority_queue for dijkstra, it reduces the complexity to O(E*logV) but it guarentees us that when we pop a node from the heap, we have found the shortest distance to that node. So, whenever I pop a node from the heap, I set processed[node] = true. Then, when I relax any of its neighbors, I don't check if they are processed because I know that if a node can be relaxed, i.e. we found a distance that is smaller than the prev dist computed for it, then that means the node cannot have been processed.

Just to double check, I put a if statement that prints something if processed[v] is true (which, as I said above, should never happen) inside the portion of the code that relaxes node v. However, this fails in some Codeforces test cases because the if statement prints which I don't understand why. I ran this code on https://codeforces.net/problemset/problem/20/C

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

using ll = long long;

#define pc(x) putchar(x)
#define gc() getchar()

inline void writeInt(int n)
{
	int N = n, rev, count = 0;
	rev = N;
	if (N == 0)
	{
		pc('0');
		pc('\n');
		return;
	}
	while ((rev % 10) == 0)
	{
		count++;
		rev /= 10;
	}
	rev = 0;
	while (N != 0)
	{
		rev = (rev << 3) + (rev << 1) + N % 10;
		N /= 10;
	}
	while (rev != 0)
	{
		pc(rev % 10 + '0');
		rev /= 10;
	}
	while (count--)
		pc('0');
	pc(' ');
}

inline int FAST_IO()
{
	char ch;
	int val = 0;
	ch = gc();
	while (ch == '\n' || ch == ' ')
		ch = gc();
	val = 0;
	while (ch >= '0' && ch <= '9')
	{
		val = (val * 10) + (ch - '0');
		ch = gc();
	}
	return val;
}

int n, m;

void print(const vector<int> &parent, int n)
{
	if (n == -1)
		return;
	print(parent, parent[n]);
	writeInt(n);
}


int main()
{
	std::ios::sync_with_stdio(false);
	cin.tie(nullptr);
	cout.tie(nullptr);

	n = FAST_IO();
	m = FAST_IO();
	vector<vector<pair<int, ll>>> adj(n + 1);
	vector<int> parent(n + 1, -1);
	vector<ll> dist(n + 1, LLONG_MAX);
	vector<bool> processed(n + 1, false);

	while (m--)
	{
		int u = FAST_IO();
		int v = FAST_IO();
		int w = FAST_IO();
		adj[u].emplace_back(v, w);
		adj[v].emplace_back(u, w);
	}

	auto cmp = [&dist](const int &a, const int &b)
	{
		return dist[a] > dist[b];
	};

	priority_queue<int, vector<int>, decltype(cmp)> pq(cmp);

	pq.push(1);
	dist[1] = 0;
	while (!pq.empty())
	{
		int u = pq.top();
		pq.pop();
		
		if (u == n)
			break;
		if (processed[u])
			continue;
		processed[u] = true;


		for (auto &[v, w] : adj[u])
		{
			if (dist[u] + w < dist[v]) // if this is true then processed[v] should be false?
			{
				//v can be relaxed -> processed[v] is false

				if (processed[v]) // THIS CODE SHOULD NEVER RUN BUT IT DOES??
				     cout << "dv = " << dist[v] << "\tdu + w = " << (dist[u] + w) << '\n';

				dist[v] = dist[u] + w;
				parent[v] = u;
				// if (!processed[v])//redundant
				pq.push(v);
			}
		}
	}

	if (dist[n] < LLONG_MAX)
		print(parent, n);
	else
		printf("-1");

	return 0;
}
Tags c++, dijkstra, shortest path, heap

History

 
 
 
 
Revisions
 
 
  Rev. Lang. By When Δ Comment
en1 English ayushkoul00 2022-04-05 16:01:39 3158 Initial revision (published)