Skip to content

Graph Input Methods for Competitive Programming

A comprehensive guide for building adjacency matrices and adjacency lists from standard input in C++ for HackerRank and LeetCode problems.

Best for dense graphs with small n (≤ 1000) due to O(n²) space complexity.

#include <iostream>
#include <vector>
using namespace std;
void buildAdjacencyMatrix() {
int n, m; // n = nodes, m = edges
cin >> n >> m;
// Create adjacency matrix (1-indexed)
vector<vector<int>> adj(n + 1, vector<int>(n + 1, 0));
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u][v] = 1; // For directed graph
adj[v][u] = 1; // Add this line for undirected graph
}
// Usage: check if edge exists between u and v
// if (adj[u][v]) { /* edge exists */ }
}

Input Format:

5 6
1 2
2 3
3 4
4 5
5 1
2 4

Ideal for algorithms like Floyd-Warshall shortest path.

void buildWeightedAdjacencyMatrix() {
int n, m;
cin >> n >> m;
// Initialize with infinity (or large value)
const int INF = 1e9;
vector<vector<int>> adj(n + 1, vector<int>(n + 1, INF));
// Distance from node to itself is 0
for (int i = 1; i <= n; i++) {
adj[i][i] = 0;
}
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
adj[u][v] = w;
adj[v][u] = w; // For undirected graph
}
}

Input Format:

4 5
1 2 10
2 3 20
3 4 30
4 1 40
1 3 50

Method 3: Adjacency List (Vector of Vectors)

Section titled “Method 3: Adjacency List (Vector of Vectors)”

Most commonly used method - memory efficient for sparse graphs.

void buildAdjacencyList() {
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n + 1); // 1-indexed
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u); // Remove for directed graph
}
// Usage: iterate through neighbors of node u
// for (int neighbor : adj[u]) { /* process neighbor */ }
}

Using pairs to store both neighbor and edge weight.

void buildWeightedAdjacencyList() {
int n, m;
cin >> n >> m;
vector<vector<pair<int, int>>> adj(n + 1);
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
adj[u].push_back({v, w}); // {neighbor, weight}
adj[v].push_back({u, w}); // For undirected graph
}
// Usage: iterate through weighted edges
// for (auto& edge : adj[u]) {
// int neighbor = edge.first;
// int weight = edge.second;
// }
}

Useful for sparse graphs or when node labels aren’t sequential.

#include <unordered_map>
void buildAdjacencyListMap() {
int m;
cin >> m;
unordered_map<int, vector<int>> adj;
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u); // For undirected graph
}
// Usage: check if node exists before accessing
// if (adj.find(u) != adj.end()) {
// for (int neighbor : adj[u]) { /* process */ }
// }
}

Stores edges separately - useful for algorithms like Kruskal’s MST.

void buildEdgeList() {
int n, m;
cin >> n >> m;
vector<pair<int, int>> edges; // For unweighted
// vector<tuple<int, int, int>> weightedEdges; // For weighted: {u, v, weight}
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
edges.push_back({u, v});
// For weighted version:
// int w;
// cin >> u >> v >> w;
// weightedEdges.push_back({u, v, w});
}
}
void standardGraphInput() {
int n, m; // n = nodes, m = edges
cin >> n >> m;
vector<vector<int>> adj(n + 1); // 1-indexed
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u); // Remove for directed graph
}
}
void treeInput() {
int n;
cin >> n;
vector<vector<int>> adj(n + 1);
for (int i = 0; i < n - 1; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u);
}
}
void gridInput() {
int rows, cols;
cin >> rows >> cols;
vector<string> grid(rows);
for (int i = 0; i < rows; i++) {
cin >> grid[i];
}
// Convert grid to adjacency list
vector<vector<int>> adj(rows * cols);
// Directions: up, down, left, right
int dx[] = {-1, 1, 0, 0};
int dy[] = {0, 0, -1, 1};
for (int i = 0; i < rows; i++) {
for (int j = 0; j < cols; j++) {
if (grid[i][j] == '#') continue; // Skip walls
int current = i * cols + j; // Convert 2D to 1D index
for (int d = 0; d < 4; d++) {
int ni = i + dx[d];
int nj = j + dy[d];
if (ni >= 0 && ni < rows && nj >= 0 && nj < cols && grid[ni][nj] != '#') {
int neighbor = ni * cols + nj;
adj[current].push_back(neighbor);
}
}
}
}
}

Always include this for competitive programming:

void setupFastIO() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
cout.tie(NULL);
}
int main() {
setupFastIO();
// Your code here
return 0;
}
5 6
1 2
2 3
3 4
4 5
5 1
2 4
4 5
1 2 10
2 3 20
3 4 30
4 1 40
1 3 50
5
1 2
2 3
2 4
4 5
3 4
....
.##.
....
  • Adjacency List: O(V + E) space - preferred for sparse graphs
  • Adjacency Matrix: O(V²) space - only use when V ≤ 1000
MethodBest ForSpace ComplexityTime to Check Edge
Adjacency MatrixDense graphs, small VO(V²)O(1)
Adjacency ListSparse graphs, large VO(V + E)O(degree)
Edge ListMST, Edge-based algorithmsO(E)O(E)
  • Forgetting to handle directed vs undirected graphs
  • Using wrong indexing (0-based vs 1-based)
  • Not setting up fast I/O for large inputs
  • Using adjacency matrix for large graphs (memory limit exceeded)
#include <iostream>
#include <vector>
#include <unordered_map>
using namespace std;
void solve() {
int n, m;
cin >> n >> m;
vector<vector<int>> adj(n + 1); // Choose appropriate method
for (int i = 0; i < m; i++) {
int u, v;
cin >> u >> v;
adj[u].push_back(v);
adj[v].push_back(u); // For undirected
}
// Your algorithm here
}
int main() {
ios_base::sync_with_stdio(false);
cin.tie(NULL);
solve();
return 0;
}