D - Maze Runner
Subtask 1
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Solution {
public:
/**
* @param n: Number of nodes
* @param m: Number of edges
* @param corridors:a vector of vector of integers where each element is a
* tuple (u, v, w) that represent a corridor between room u and room v with
* speed requirement w (1-indexed)
* @return: the speed required to run from room 1 to room n
*/
static void dfs(int x, int pa, const vector<vector<pair<int, int>>>& e,
int& ans, int cur, int n) {
if (x == n) {
ans = cur;
return;
}
for (auto [u, w] : e[x]) {
if (u == pa) continue;
dfs(u, x, e, ans, max(cur, w), n);
}
}
static int solve(int n, int m, std::vector<std::vector<int>>& edges) {
// Implement your solution by completing the following function
int ans = 0;
vector<vector<pair<int, int>>> e;
e.resize(n + 1);
for (auto x : edges) {
e[x[0]].push_back(make_pair(x[1], x[2]));
e[x[1]].push_back(make_pair(x[0], x[2]));
}
dfs(1, 1, e, ans, 0, n);
return ans;
}
};
int main() {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<int>> edges(m, std::vector<int>(3));
for (int i = 0; i < m; ++i) {
std::cin >> edges[i][0] >> edges[i][1] >> edges[i][2];
}
int ans = Solution::solve(n, m, edges);
std::cout << ans << std::endl;
return 0;
}
Subtask 2
#include <algorithm>
#include <cmath>
#include <iostream>
#include <queue>
#include <vector>
using namespace std;
class Solution {
public:
/**
* @param n: Number of nodes
* @param m: Number of edges
* @param corridors:a vector of vector of integers where each element is a
* tuple (u, v, w) that represent a corridor between room u and room v with
* speed requirement w (1-indexed)
* @return: the speed required to run from room 1 to room n
*/
static void dfs(int x, int pa, const vector<vector<pair<int, int>>>& e,
int& ans, int cur, int n, vector<int>& vis) {
if (x == n) {
ans = cur;
return;
}
vis[x] = 1;
for (auto [u, w] : e[x]) {
if (u == pa || vis[u]) continue;
dfs(u, x, e, ans, max(cur, w), n, vis);
}
}
static int solve(int n, int m, std::vector<std::vector<int>>& edges) {
// Implement your solution by completing the following function
int ans = 0;
for (int v = 1; v <= 1e9; v <<= 1) {
vector<int> vis(n + 1, 0);
vector<vector<pair<int, int>>> e;
e.resize(n + 1);
for (auto x : edges) {
if (x[2] > v) continue;
e[x[0]].push_back(make_pair(x[1], x[2]));
e[x[1]].push_back(make_pair(x[0], x[2]));
}
ans = 0;
dfs(1, 1, e, ans, 0, n, vis);
if (ans) {
return v;
}
}
return ans;
}
};
int main() {
int n, m;
std::cin >> n >> m;
std::vector<std::vector<int>> edges(m, std::vector<int>(3));
for (int i = 0; i < m; ++i) {
std::cin >> edges[i][0] >> edges[i][1] >> edges[i][2];
}
int ans = Solution::solve(n, m, edges);
std::cout << ans << std::endl;
return 0;
}
Solution (Minimum Spanning Tree)
-
from typing import List, Tuple # If you want to use a deep recursion, you need to increase the recursion limit # Python's default recursion limit is 1000 # Uncomment the following two lines if you need to use deep recursion # import sys # sys.setrecursionlimit(10**8) class Solution: @staticmethod def solve( n: int, m: int, corridors: List[Tuple[int, int, int]], ) -> int: """ Args: n: Number of rooms m: Number of corridors corridors: List of corridors as (u, v, w) tuple where u and v are 1-indexed node IDs. Returns: int: The minimum speed required to run from room 1 to room n """ if n == 1: return 0 parent = list(range(n + 1)) def find(i: int) -> int: if parent[i] == i: return i parent[i] = find(parent[i]) return parent[i] def union(i: int, j: int): root_i = find(i) root_j = find(j) if root_i != root_j: parent[root_i] = root_j corridors.sort(key=lambda x: x[2]) for u, v, w in corridors: union(u, v) if find(1) == find(n): return w return -1 if __name__ == "__main__": n, m = map(int, input().split()) corridors = [] for _ in range(m): u, v, w = map(int, input().split()) corridors.append((u, v, w)) result = Solution.solve(n, m, corridors) print(result) -
/** * This template provides a complete implementation of a graph data structure * using a dynamic adjacency list representation. The implementation is designed * to be efficient for graph algorithms and problems. * * Adjacency List Implementation: * - Each node in the graph maintains its own list of neighbors (adjacent nodes) * - The neighbor list is implemented as a dynamic array that grows as needed * - Initial capacity is small (NEIGHBORS_INITIAL_CAP) and doubles when full * - This approach balances memory usage and performance * * Key Features: * - Dynamic memory allocation for efficient space usage * - O(1) edge insertion * - O(degree) time complexity for traversing neighbors of a node * - Support for undirected graphs * * Usage: * 1. Create a graph with get_graph(N) where N is the number of nodes * 2. Add edges with add_edge(graph, u, v) where u and v are node IDs * 3. Access neighbors of node i with graph->nodes[i].neighbors * 4. Number of neighbors is stored in graph->nodes[i].neighborsSize * 5. Remember to free the graph with free_graph() when done * * Note: All node IDs are 0-indexed in the internal representation * Input/output may use 1-indexed IDs, requiring conversion * */ #include <memory.h> #include <stdbool.h> #include <stdio.h> #include <stdlib.h> #define NEIGHBORS_INITIAL_CAP 4 // Initial capacity for neighbors array /** * @struct Guard * @brief Represents a guard with position and movement range */ typedef struct { int from; // Node where corridor starts int to; // Node where corridor ends int speed; // speed requirement of the corridor } Corridor; /** * @struct Node * @brief Represents a node in the graph */ typedef struct { int id; // Node identifier Corridor *neighbors; // Dynamic array of connecting corridors int neighborsSize; // Current number of neighbors int neighborsCap; // Current capacity of neighbors array } Node; /** * @struct Graph * @brief Represents the entire graph */ typedef struct { Node *nodes; // Array of all nodes int nodesSize; // Number of nodes in the graph } Graph; /** * @brief Initialize a node with given ID * @param node Pointer to the node to initialize * @param id ID to assign to the node */ void init_node(Node *node, int id) { node->id = id; node->neighborsSize = 0; node->neighborsCap = NEIGHBORS_INITIAL_CAP; node->neighbors = calloc(node->neighborsCap, sizeof(Corridor)); if (node->neighbors == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } } /** * @brief Free memory allocated for a node * @param node Pointer to the node to free */ void free_node(Node *node) { free(node->neighbors); } /** * @brief Create a new graph with specified number of nodes * @param nodesSize Number of nodes in the graph * @return Pointer to the created graph */ Graph *get_graph(int nodesSize) { Graph *graph = malloc(sizeof(Graph)); if (graph == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } graph->nodesSize = nodesSize; graph->nodes = calloc(nodesSize, sizeof(Node)); if (graph->nodes == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } for (int i = 0; i < nodesSize; ++i) { init_node(&graph->nodes[i], i); } return graph; } /** * @brief Free memory allocated for a graph * @param graph Pointer to the graph to free */ void free_graph(Graph *graph) { for (int i = 0; i < graph->nodesSize; i++) { free_node(&graph->nodes[i]); } free(graph->nodes); } /** * @brief Add a neighbor to a node's neighbor list * @param node Pointer to the node * @param neighbor ID of the neighbor to add */ void insert_neighbor(Node *node, Corridor corridor) { // Double capacity if needed if (node->neighborsSize == node->neighborsCap) { node->neighborsCap *= 2; node->neighbors = realloc(node->neighbors, node->neighborsCap * sizeof(Corridor)); if (node->neighbors == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } } node->neighbors[node->neighborsSize++] = corridor; } /** * @brief Add an undirected edge between two nodes in the graph * @param graph Pointer to the graph * @param u First node ID * @param v Second node ID */ void add_edge(Graph *graph, int u, int v, int speed) { if (u >= graph->nodesSize || v >= graph->nodesSize) { fprintf(stderr, "Invalid node id\n"); exit(1); } Corridor c; c.from = u; c.to = v; c.speed = speed; insert_neighbor(&graph->nodes[u], c); c.from = v; c.to = u; insert_neighbor(&graph->nodes[v], c); } /** * @brief Comparison function for qsort to sort node IDs */ int cmp_result(const void *a, const void *b) { return *(int *)a - *(int *)b; } // DSU find function with path compression int find_set(int v, int *parent) { if (v == parent[v]) return v; return parent[v] = find_set(parent[v], parent); } // DSU union function void unite_sets(int a, int b, int *parent) { a = find_set(a, parent); b = find_set(b, parent); if (a != b) parent[b] = a; } // Comparison function for qsort to sort Corridors by speed int cmp_corridor(const void *a, const void *b) { Corridor *c1 = (Corridor *)a; Corridor *c2 = (Corridor *)b; if (c1->speed < c2->speed) return -1; if (c1->speed > c2->speed) return 1; return 0; } /** * @param n Number of room * @param m Number of corridors * @param graph Pointer to the graph (room are in 1-indexed) * @return The minimum speed required to run from room 1 to room n */ int solve(int n, int m, Graph *graph) { if (n == 1) { return 0; } if (m == 0) { return -1; } Corridor *corridors = malloc(m * sizeof(Corridor)); if (corridors == NULL) { fprintf(stderr, "Memory allocation failed\n"); exit(1); } int corridor_count = 0; for (int i = 1; i <= n; ++i) { Node node = graph->nodes[i]; for (int j = 0; j < node.neighborsSize; ++j) { Corridor c = node.neighbors[j]; if (c.from < c.to) { if (corridor_count < m) { corridors[corridor_count++] = c; } } } } qsort(corridors, m, sizeof(Corridor), cmp_corridor); int *parent = malloc((n + 1) * sizeof(int)); if (parent == NULL) { fprintf(stderr, "Memory allocation failed\n"); free(corridors); exit(1); } for (int i = 0; i <= n; i++) { parent[i] = i; } int result = -1; for (int i = 0; i < m; i++) { unite_sets(corridors[i].from, corridors[i].to, parent); if (find_set(1, parent) == find_set(n, parent)) { result = corridors[i].speed; break; } } free(parent); free(corridors); return result; } /** * @brief Main function to read input, solve the problem, and output results */ int main() { int n, m; scanf("%d%d", &n, &m); // Create graph with n nodes Graph *graph = get_graph(n + 1); // Read m edges for (int i = 0; i < m; ++i) { int u, v, w; scanf("%d%d%d", &u, &v, &w); add_edge(graph, u, v, w); } int result = solve(n, m, graph); printf("%d\n", result); // Clean up free_graph(graph); free(graph); return 0; } -
#include <bits/stdc++.h> using namespace std; struct dsu { vector<int> parent; int n; dsu(int n) : n(n) { parent.resize(n); iota(parent.begin(), parent.end(), 0); } int find(int u) { return (parent[u] == u) ? u : parent[u] = find(parent[u]); } void merge(int u, int v) { u = find(u); v = find(v); if (u != v) parent[u] = v; } }; int main() { int n, m; cin >> n >> m; vector<tuple<int, int, int>> edges(m); for (int i = 0; i < m; i++) { int u, v, w; cin >> u >> v >> w; u--, v--; edges[i] = {w, u, v}; } sort(edges.begin(), edges.end()); int ans = 0; dsu d(n); for (auto& [w, u, v] : edges) { d.merge(u, v); if (d.find(0) == d.find(n - 1)) { ans = w; break; } } cout << ans << '\n'; } -
import java.util.ArrayList; import java.util.Comparator; import java.util.List; import java.util.Scanner; // even though the data is from and to. But it is an undirected edge. The From and To is just for // adjacentcy listpurpose class Corridor { int from; int to; int w; Corridor(int from, int to, int w) { this.from = from; this.to = to; this.w = w; } } class Graph { List<List<Corridor>> adj; Graph(int n) { adj = new ArrayList<>(); for (int i = 0; i <= n; i++) { adj.add(new ArrayList<>()); } } public void addEdge(int u, int v, int w) { adj.get(u).add(new Corridor(u, v, w)); adj.get(v).add(new Corridor(v, u, w)); } public List<Corridor> getListOfAdjecentNodes(int u) { return adj.get(u); } } class Solution { static class DSU { int[] parent; DSU(int n) { parent = new int[n + 1]; for (int i = 0; i <= n; i++) { parent[i] = i; } } int find(int x) { if (parent[x] != x) { parent[x] = find(parent[x]); } return parent[x]; } void union(int x, int y) { int rootX = find(x); int rootY = find(y); if (rootX != rootY) { parent[rootX] = rootY; } } } /** * @param n: number of rooms * @param m: number of corridors * @param corridors: list of Corridor objects (u, v, w) representing a corridor between room u and * room v with speed requirement w, where u and v are 1-indexed node IDs. * @return: return an integer representing the minimum speed required to run from room 1 to room n */ static int solve(int n, int m, List<Corridor> corridors) { if (n == 1) { return 0; } corridors.sort(Comparator.comparingInt(c -> c.w)); DSU dsu = new DSU(n); for (Corridor corridor : corridors) { dsu.union(corridor.from, corridor.to); if (dsu.find(1) == dsu.find(n)) { return corridor.w; } } return -1; } // ALTERNATIVE /** * @param n: number of rooms * @param m: number of corridors * @param maze: an adjacency list representing the maze, where maze[i] contains list of room * adjacent to it and the speed requirement of the corridor connecting them. * @return: return an integer representing the minimum speed required to run from room 1 to room n */ static int solve(int n, int m, Graph maze) { // Implement your solution here return 0; } public static void main(String[] args) throws java.lang.Exception { Scanner input = new Scanner(System.in); int n = input.nextInt(); int m = input.nextInt(); List<Corridor> corridors = new ArrayList<>(); Graph maze = new Graph(n + 1); for (int i = 0; i < m; i++) { int u, v, w; u = input.nextInt(); v = input.nextInt(); w = input.nextInt(); corridors.add(new Corridor(u, v, w)); maze.addEdge(u, v, w); } int ans1 = solve(n, m, corridors); int ans2 = solve(n, m, maze); int ans = ans1; if (ans1 == 0 && n > 1) ans = ans2; System.out.println(ans); input.close(); } } -
use std::io; fn find(x: usize, fa: &mut [i32]) -> i32 { if fa[x] != x as i32 { fa[x] = find(fa[x] as usize, fa); } fa[x] } fn main() { let mut input = String::new(); io::stdin().read_line(&mut input).expect("Failed to read line"); let nums: Vec<usize> = input .trim() .split_whitespace() .map(|s| s.parse().expect("")) .collect(); let (n, m) = (nums[0], nums[1]); let mut edges = Vec::new(); for _ in 0..m { input.clear(); io::stdin().read_line(&mut input).expect("Failed to read line"); let edge: Vec<usize> = input .trim() .split_whitespace() .map(|s| s.parse().expect("")) .collect(); let (u, v, w) = (edge[0], edge[1], edge[2]); edges.push((u, v, w)); } edges.sort_by_key(|x| x.2); let mut fa: Vec<i32> = (0..=n as i32).collect(); for i in 0..m { let (u, v, w) = edges[i]; let fu = find(u, &mut fa); let fv = find(v, &mut fa); if fu != fv { fa[fu as usize] = fv; } if find(1, &mut fa) == find(n, &mut fa) { println!("{}", w); return; } } println!("-1"); }
Solution (Binary Search On Answer)
#include <bits/stdc++.h>
using namespace std;
int main() {
int n, m;
cin >> n >> m;
vector<vector<pair<int, int> > > adj(n);
for (int i = 0; i < m; i++) {
int u, v, w;
cin >> u >> v >> w;
u--, v--;
adj[u].emplace_back(v, w);
adj[v].emplace_back(u, w);
}
vector<int> visited(n);
int limit;
function<void(int)> dfs = [&](int u) {
visited[u] = 1;
for (auto& [v, w] : adj[u]) {
if (!visited[v] && w <= limit) dfs(v);
}
};
int l = 1, r = 1e9;
while (l < r) {
int mid = (l + r) / 2;
visited.assign(n, 0);
limit = mid;
dfs(0);
if (visited[n - 1])
r = mid;
else
l = mid + 1;
}
cout << l << "\n";
}