SPFA Algorithm Templates, CSPJ Problem Solutions, and Common Data Structure Patterns

SPFA Shortest Path Algorithm

The Shortest Path Faster Algorithm (SPFA) is an optimization of the Bellman-Ford algorithm that uses a queue to process vertices and provides efficient shortest path computation in graphs with negative edge weights.

Standard SPFA Implementation


#define MAX_VERTICES 400002
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

struct Edge {
    int destination;
    int weight;
};

int vertexCount, edgeCount;
vector<Edge> graph[MAX_VERTICES];
int distanceArray[MAX_VERTICES];
bool inQueue[MAX_VERTICES];
queue<int> vertexQueue;

void shortestPathFasterAlgorithm(int source) {
    int current, neighbor;
    
    // Initialize distances to infinity
    for (int i = 1; i <= vertexCount; i++) {
        distanceArray[i] = INT_MAX;
    }
    distanceArray[source] = 0;
    
    vertexQueue.push(source);
    inQueue[source] = true;
    
    // Process vertices in queue
    while (!vertexQueue.empty()) {
        current = vertexQueue.front();
        vertexQueue.pop();
        inQueue[current] = false;
        
        // Relax all outgoing edges
        for (int i = 0; i < graph[current].size(); i++) {
            neighbor = graph[current][i].destination;
            
            if (distanceArray[neighbor] > distanceArray[current] + graph[current][i].weight) {
                distanceArray[neighbor] = distanceArray[current] + graph[current][i].weight;
                
                if (!inQueue[neighbor]) {
                    vertexQueue.push(neighbor);
                    inQueue[neighbor] = true;
                }
            }
        }
    }
}

int main() {
    int u, v, type, time;
    
    cin >> vertexCount >> edgeCount;
    
    for (int i = 1; i <= edgeCount; i++) {
        cin >> u >> v >> type >> time;
        graph[u].push_back({v, time});
    }
    
    shortestPathFasterAlgorithm(1);
    
    // Output distances from vertex 2 to n
    for (int i = 2; i <= vertexCount; i++) {
        if (distanceArray[i] == INT_MAX) {
            cout << "-1 ";
        } else {
            cout << distanceArray[i] << ' ';
        }
    }
    return 0;
}

SPFA for Layered Graph Problems

When dealing with layered graph problems where edges can connect different layers or stay within the same layer, we extend the vertex space to accommodate both layers:


#define MAX_VERTICES 400002
#include <iostream>
#include <vector>
#include <queue>
using namespace std;

struct Edge {
    int destination;
    int weight;
};

int vertexCount, edgeCount;
vector<Edge> graph[MAX_VERTICES];
int distanceArray[MAX_VERTICES];
bool inQueue[MAX_VERTICES];
queue<int> vertexQueue;

void shortestPathFasterAlgorithm(int source) {
    int current, neighbor;
    
    // Initialize distances for all vertices across both layers
    for (int i = 1; i <= 2 * vertexCount; i++) {
        distanceArray[i] = INT_MAX;
    }
    distanceArray[source] = 0;
    
    vertexQueue.push(source);
    inQueue[source] = true;
    
    while (!vertexQueue.empty()) {
        current = vertexQueue.front();
        vertexQueue.pop();
        inQueue[current] = false;
        
        for (int i = 0; i < graph[current].size(); i++) {
            neighbor = graph[current][i].destination;
            
            if (distanceArray[neighbor] > distanceArray[current] + graph[current][i].weight) {
                distanceArray[neighbor] = distanceArray[current] + graph[current][i].weight;
                
                if (!inQueue[neighbor]) {
                    vertexQueue.push(neighbor);
                    inQueue[neighbor] = true;
                }
            }
        }
    }
}

int main() {
    int u, v, type, time;
    
    cin >> vertexCount >> edgeCount;
    
    for (int i = 1; i <= edgeCount; i++) {
        cin >> u >> v >> type >> time;
        
        if (type == 1) {
            // Same-layer connections
            graph[u].push_back({v, time});           // Layer 1: u -> v
            graph[u + vertexCount].push_back({v + vertexCount, time});  // Layer 2: (u+n) -> (v+n)
        } else {
            // Cross-layer connections
            graph[u].push_back({v + vertexCount, time});  // Layer 1 to Layer 2: u -> v+n
        }
    }
    
    shortestPathFasterAlgorithm(1);
    
    // Take minimum distance from both layers
    for (int i = 2; i <= vertexCount; i++) {
        int result = min(distanceArray[i], distanceArray[i + vertexCount]);
        if (result == INT_MAX) {
            cout << "-1 ";
        } else {
            cout << result << ' ';
        }
    }
    return 0;
}

Extracting and Sorting Digits

Two common approaches for extracting digits from a string and sorting them in descending order:

Using Priority Queue


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

string input;
priority_queue<int> digitQueue;

int main() {
    cin >> input;
    
    for (char c : input) {
        if (c >= '0' && c <= '9') {
            digitQueue.push(c - '0');
        }
    }
    
    while (!digitQueue.empty()) {
        cout << digitQueue.top();
        digitQueue.pop();
    }
    return 0;
}

Using Counting Sort


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

string input;
int digitCount[10];

int main() {
    cin >> input;
    
    for (char c : input) {
        if (c >= '0' && c <= '9') {
            digitCount[c - '0']++;
        }
    }
    
    for (int d = 9; d >= 0; d--) {
        while (digitCount[d] > 0) {
            cout << d << ' ';
            digitCount[d]--;
        }
    }
    return 0;
}

Matrix Posision Calculation

Given a sequence of values, calculate the position of a specific element in a zigzag matrix:


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

int values[102];
int rowCount, columnCount;

void findPosition() {
    int targetValue, currentIndex = 0;
    int greaterCount = 0, position;
    int targetRow, targetColumn, temp;
    
    cin >> rowCount >> columnCount;
    cin >> values[1];
    targetValue = values[1];
    
    // Count elements greater than target
    for (int i = 2; i <= rowCount * columnCount; i++) {
        cin >> values[i];
        if (values[i] > targetValue) {
            greaterCount++;
        }
    }
    
    position = greaterCount + 1;
    
    // Sort in descending order
    sort(values + 1, values + 1 + rowCount * columnCount, greater<int>());
    
    // Calculate row and column
    if (position % rowCount == 0) {
        targetRow = position / rowCount;
    } else {
        targetRow = position / rowCount + 1;
    }
    
    temp = position - (targetRow - 1) * rowCount;
    
    // Handle zigzag column ordering
    if (targetRow % 2 == 1) {
        targetColumn = temp;
    } else {
        targetColumn = rowCount + 1 - temp;
    }
    
    cout << targetRow << ' ' << targetColumn << endl;
}

int main() {
    findPosition();
    return 0;
}

XOR Subarray Problem

Find the maximum number of non-overlapping subarrays where the XOR equals k using prefix XOR technique:


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

int arraySize, targetXor;
int arrayValues[500001];
int prefixXor[500001];
int lastPosition[500001];

int main() {
    int currentXor, requiredXor;
    int result = 0, lastValidEnd = 0;
    int index;
    
    cin >> arraySize >> targetXor;
    
    for (int i = 1; i <= arraySize; i++) {
        cin >> arrayValues[i];
    }
    
    // Initialize with boundary condition
    memset(lastPosition, -1, sizeof(lastPosition));
    lastPosition[0] = 0;  // Empty prefix has XOR 0
    
    for (index = 1; index <= arraySize; index++) {
        prefixXor[index] = prefixXor[index - 1] ^ arrayValues[index];
        requiredXor = prefixXor[index] ^ targetXor;
        
        // Check if we can extend from last valid position
        if (lastPosition[requiredXor] >= lastValidEnd) {
            result++;
            lastValidEnd = index;
        }
        
        // Record the latest position of this prefix XOR
        lastPosition[prefixXor[index]] = index;
    }
    
    cout << result << endl;
    return 0;
}

C++ Set Container and String Hashing

The std::set container provides O(log n) operations for inserting, deleting, and searching elements while maintaining sorted order:


// Set container operations
set<int> numberSet;

// Insert elements
numberSet.insert(10);
numberSet.insert(8);
numberSet.insert(20);

// Iterate through set
for (auto iterator = numberSet.begin(); iterator != numberSet.end(); iterator++) {
    cout << *iterator << ' ';
}

// Erase element
numberSet.erase(10);

// Get size
cout << numberSet.size() << endl;

// Check existence using count
if (numberSet.count(20) == 1) {
    cout << "found" << endl;
}

// Find element
int searchValue = 15;
auto findResult = numberSet.find(searchValue);
if (findResult != numberSet.end()) {
    cout << "found" << endl;
}

// String set for unique strings
set<string> stringSet;
string input;
int count;

cin >> count;
for (int i = 0; i < count; i++) {
    cin >> input;
    stringSet.insert(input);
}

cout <> stringSet.size();

Tower of Hanoi

The Tower of Hanoi problem demonstrates recursive problem-solving where a larger problem is decomposed into smaller subproblems of the same type:

Classic Three-Peg Solution


// Recursive Hanoi solution for 3 pegs
// Parameters: number of disks, source peg, auxiliary peg, destination peg
void hanoiThreePegs(int diskCount, char source, char auxiliary, char destination) {
    if (diskCount == 1) {
        // Base case: single disk moves directly
        cout << source << " -> " << destination << endl;
        return;
    }
    
    // Move n-1 disks to auxiliary peg
    hanoiThreePegs(diskCount - 1, source, destination, auxiliary);
    
    // Move largest disk to destination
    cout << source << " -> " << destination << endl;
    
    // Move n-1 disks from auxiliary to destination
    hanoiThreePegs(diskCount - 1, auxiliary, source, destination);
}

Four-Peg Optimization

For the four-peg variant (Reve's Puzzle), the optimal strategy divides disks into two groups:


// Optimal 4-peg Hanoi solution
// Split n disks into k and n-k groups
void hanoiFourPegs(int diskCount, int k, char source, char auxiliary1, char auxiliary2, char destination) {
    if (diskCount == 0) return;
    
    if (diskCount == 1) {
        cout << source << " -> " << destination << endl;
        return;
    }
    
    // Step 1: Move top k disks from source to first auxiliary (using all 4 pegs)
    hanoiFourPegs(k, k, source, destination, auxiliary2, auxiliary1);
    
    // Step 2: Move remaining n-k disks from source to destination (using 3 pegs)
    hanoiThreePegs(diskCount - k, source, auxiliary2, destination);
    
    // Step 3: Move k disks from auxiliary to destination (using all 4 pegs)
    hanoiFourPegs(k, k, auxiliary1, source, auxiliary2, destination);
}

Pointer Fundamentals

Pointers enable indirect access and modification of memory locations, supporting complex data structures and memory management:


void pointerExamples() {
    int original = 78;
    
    // Single-level pointer
    int *firstLevel = &original;
    
    // Multi-level pointer
    int **secondLevel = &firstLevel;
    
    // Modify original through different access methods
    *firstLevel = 87;          // Direct modification via first-level pointer
    **secondLevel = 87;        // Modification via second-level pointer
    
    // Note: The pointer variable address itself cannot be modified
    // The pointer stores an address that can be changed, but the address
    // stored in memory (the pointer variable) is what we manipulate
}

Tags: SPFA algorithm C++ priority-queue set-container

Posted on Wed, 28 Oct 2026 16:35:27 +0000 by thetick