POJ 3259 Wormholes wormholes problem

Posted by Danno13 on Sun, 16 Jan 2022 17:42:25 +0100

The link to the question is here.

Obviously, this problem is to detect the negative weight loop (the cost of returning to the initial point along a path is negative.)
Firstly, Bellman Ford algorithm and improved spfa algorithm are introduced here.

1. Bellman Ford algorithm

Bellman Ford is also an algorithm that can find the shortest path of the element. Different from Dijkstra algorithm, it can be used to judge whether the negative weight edge exists.

Relaxation function

First, let's introduce what the relaxation function is. Although the relaxation function sounds very tall, I have actually learned a little about the data structure and soon understand what it is. Let the path weight from the source point to point v be s[v]. If u is an element of the edge set and the weight w(u,v) from edge u to V makes s[u]+w(u,v) < s[v], then update the weight of s[v] to s[u]+w(u,v), which is equivalent to relaxation, This is the relaxation function.

The number of times the relaxation function is executed

Now consider relaxing each edge in the edge set E as an iteration, and consider the number of iterations required. Obviously, the traversal order of each iteration edge is very important. If each relaxation can reduce the s value of a vertex, we can quickly obtain the single source shortest path of the source vertex; If each traversal can only relax one vertex successfully (at least one vertex must be relaxed for each traversal, unless the single source shortest path has been obtained), n iterations are required. (n is the number of vertices) therefore, one iteration is required in the best case and N-1 iteration is required in the worst case.

Bellman Ford algorithm

Bellman Ford algorithm uses the above relaxation function and iterates continuously until the shortest single source path is found. We can feel that bellmanford algorithm is a little similar to dijkstra algorithm, which constantly ensures the shortest path from a node to the source point, so as to finally obtain the shortest path of a single source. The difference is that the relaxation function does not know which node is determined in a relaxation, but only knows that at least one node must be determined, while dijkstra determines which point is determined. This difference determines that dijkstra is a typical greedy algorithm, and this greedy strategy also determines that it cannot deal with graphs with negative weight, Bellman Ford algorithm can deal with negative weight. In addition, dijkstra is more suitable for sparse graphs, that is, graphs with relatively less dense edges, while Bellman Ford is faster to solve graphs with more edges.

Can Bellman Ford algorithm determine the negative weight loop? The answer is yes, which is another advantage of Bellman Ford.

Implementation of the algorithm: because at least one edge can be relaxed at a time, the outer loop is carried out V-1 times (if an iteration fails to relax any edge, the loop exits; in addition, if there is a negative weight loop, the algorithm will not run all the time, because it can run V-1 times at most.); The edge set needs to be traversed once each time, so the inner loop is carried out E times, so its worst time complexity is O (VE). Each memory loop is relaxed once. After the execution of the loop is completed, the loop judgment is performed again. If an edge can be relaxed at this time, there must be a negative weight loop.

Skip the specific implementation process, search a lot on the Internet, and define the data structure is not a problem.

2.SPFA algorithm

First, let's introduce the principle of SPFA. Can we omit some unnecessary relaxation operations in Bellman f-ford algorithm? Consider the relaxation operation again:

Let the path weight from the source point to point v be s[v]. If u is an element of the edge set and the weight w(u,v) from edge u to V makes s[u]+w(u,v) < s[v], then update the weight of s[v] to s[u]+w(u,v), which is equivalent to relaxation. This is the relaxation function.

Node u can be relaxed because there must be a relaxed point v adjacent to it, so that s[u]+w(u,v) < s[v] can be relaxed. Because the relaxation operation must generate the source point to the relaxed node in the shortest path of the store, a data structure can be used to record the relaxed point, which can avoid redundant calculation. The commonly used data structure here is queue, which can also be improved to a certain priority queue, such as the queue with the smallest distance first or the queue with the largest distance first. I will use the ordinary first in first out queue operation here.

After using SPFA algorithm, the way of loop has changed from external loop to internal loop. How to detect the negative weight loop? This requires the data structure of the node we just recorded. Similarly, if a node can enter the queue N times, it indicates that there is a negative weight ring. This mechanism can be used to detect the negative weight ring.

The implementation process of the algorithm: first add a point to the queue, and then cycle. If the queue is not empty, cycle: queue out an element and relax all its neighbors. If a node is relaxed successfully, it will be added to the queue, and the number of queue entries of the point + 1; Then judge whether the number of times entering the queue is greater than or equal to N. if n indicates that there is a negative weight loop, exit the loop.

Time complexity: the essence is still Bellman Ford algorithm. In the worst case, the time complexity is still O (VE).

3. Concrete realization of the problem

I use the spfa algorithm here. It should be noted that the spfa algorithm obtains the shortest path of a single source, so I cycle here, and use the spfa algorithm once at each point to judge whether there is a negative weight ring.

The specific code of the problem is as follows. You can modify the data structures I use here to see how the time spent changes:

#include<iostream>
#include<queue>
using namespace std;
#define MAX 510
#define inf 0x3f3f3f3f
//**************************************************
//The problem is regarded as finding the shortest acyclic path from the origin to the origin
//SPFA algorithm and bellmanford algorithm can be used to find the shortest path of single source
//SPFA algorithm is used here 
//The general SPFA algorithm is to avoid the negative weight loop, but if there is a negative weight loop in this problem, it can be determined directly
//**************************************************
int N, W, M;
int times[MAX];
int dist[MAX];
int weight[MAX][MAX];
queue<int> q;
bool existNegativeLoop(int i) {
	if (times[i] != 0)return false;
	memset(times, 0, sizeof(times));
	times[i] = 1;
	dist[i] = 0;
	q.push(i);
	int current;
	while (!q.empty()) {
		current = q.front();
		q.pop();
		for (int j = 1; j <= N; j++) {
			if (dist[j] > dist[current] + weight[current][j]) {
				dist[j] = dist[current] + weight[current][j];
				q.push(j);
				times[j]++;
				if (times[j] >= N) return true;
			}
		}
	}
	return false;
}
int main() {
	int F;
	cin >> F;
	int i;
	int start, end, cost;
	while (F--) {
		cin >> N >> W >> M;
		memset(times, 0, sizeof(times));
		memset(weight, inf, sizeof(weight));
		//memset(dist, inf, sizeof(dist));
		//Two way road
		for (i = 0; i < W; i++) {
			cin >> start >> end >> cost;
			if (cost < weight[start][end]) {
				weight[start][end] = weight[end][start] = cost;
			}
		}
		//Unidirectional wormhole
		for (i = 0; i < M; i++) {
			cin >> start >> end >> cost;
			if (-cost < weight[start][end]) {
				weight[start][end]= -cost;
			}
		}
		//Loop checks whether each point has negative weight. Once there is one loop, it exits
		bool flag = false;
		for (i = 1; i <= N; i++) {
			memset(dist, inf, (N+1)*sizeof(int));
			if (existNegativeLoop(i)) { flag = true; break; }
		}
		if (flag) cout << "YES" << endl;
		else cout << "NO" << endl;

	}
	return 0;
}