Hard Transportation Hub

王子轩

Date: 2024-5-6

Chapter 1: Introduction

Background

Given the map of a country, there could be more than one shortest path between any pair of cities. A transportation hub is a city that is on no less than k shortest paths (the source and the destination NOT included).

Aim

Find for a given pair of cities, the transportation hubs on the way.

What we need to do

The adjacency table is used to construct the graph as a data structure, after reading the data, then Dijkstra’s algorithm is used to find the length of the shortest paths, then the backtracking algorithm is used to find all the shortest paths, and all these paths are stored in an array consisting of a chained list, and then finally traversed to find the transportation hubs as per the requirement.

Why do this

Because the comparative data is scattered, I chose to construct the graph as a data structure using an adjacency table. Because I want to find all the shortest paths, so I need to find the length of the shortest paths first, and then I can find all the shortest paths through the backtracking algorithm, in order to find the transportation hub so I need to traverse the previous paths.

Chapter 2: Algorithm Specification

data structure

  1. vertex structure:

    int dist: represents the distance of the node to the start node.

    int path: indicates the path of the node, i.e. from the start node to the parent of the current node.

    int known: indicates whether the node is known, i.e. whether the shortest path has been calculated.

  2. Edge struct:

    int dest: indicates the target node of the edge.

    int length: the length of the edge.

    struct Edge *next: pointer to other neighboring edges.

  3. PathNode struct:

    int vertex: represents the value of the path node.

    struct PathNode *next: pointer to the next node.

  4. PathList struct:

    PathNode *head: pointer to the first node.

    PathList *next: pointer to the next path list.

  5. cnt_onpath Array:

    Used to store the number of node visits through the shortest path.

  6. graph array:

    Used to store the adjacency table, representing the structure of the graph.

  7. v array:

    Used to store information about the node, including the distance from the node to the start node, the path of the node and whether the node is known.

  8. visited array:

    Used to record whether a node has been visited.

  9. pathLists array:

    Used to store a list of all paths, each path list includes a linked list of the nodes in the path.

These data structures each play different roles in the code for representing the structure of the graph, recording node information, recording paths, and implementing Dijkstra’s algorithm. By using these data structures appropriately, the path problem between nodes in the graph can be solved effectively.

Main Function

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
graph TD
A(Start) --> B(Input thresholds)
B --> C{Loop m times}
C --> D(Read edge information)
D --> E(Create edge)
E --> F(Add edge to graph)
F --> G(Create reverse edge)
G --> H(Add reverse edge to graph)
H --> C
C --> I(Read T)
I --> J(Initialize ans array)
J --> K{Loop T times}
K --> L(Initialize cnt_onpath array)
L --> M(Read src and dst)
M --> N(Initialize visited array)
N --> O(Initialize pathLists)
O --> P(Call Dijkstra's algorithm)
P --> Q(Backtrack paths)
Q --> R(Count node visits)
R --> S(Update ans array)
S --> K
K --> T(Print nodes in ans)
T --> K
T --> U(Print None)
U --> K
K --> V{Loop T times}
V --> W(Print newline)
W --> X(End)

Pseudocode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
Function main():
Declare integer variables n, m, k
Read the values of n, m, and k from the input

Loop m times:
Declare integer variables len, src, des
Read the values of src, des, and len from the input

Create a new edge with the destination des and length len
Add the new edge to the list of edges for the source vertex src

Create a new edge with the destination src and length len
Add the new edge to the list of edges for the destination vertex des

Declare an integer variable T
Read the value of T from the input

Declare a 2D integer array ans of size 505x505 and initialize it to 0

Loop T times:
Declare integer variables src, dst
Read the values of src and dst from the input

Initialize the counter array cnt_onpath

Declare an integer array visited of size 505 and initialize it to 0

Create a new pathLists object and initialize its head to a path node with destination dst

Call the Dijkstra's algorithm function with parameters n, src, and dst

Backtrack from the goal node and find all the shortest paths

Count the number of visits to nodes on all shortest paths

For each node:
If the number of 1s in its binary representation is greater than or equal to k:
Set ans[j][i] to 1

Loop T times:
Declare an integer variable flg and set it to 0

For each column j in the matrix ans:
If the element ans[i][j] is equal to 1:
If flg is 0:
Print the element
Set flg to 1
Otherwise:
Print a space followed by the element

If flg is still 0:
Print "None"

Print a newline character

Return 0

dijkstra’s algorithm: finding the length of the shortest circuit

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
graph TD
A(Start) --> B(Initialize variables)
B --> C(Set source vertex distance to 0)
C --> D(Loop until all vertices are processed)
D --> E(Find vertex with minimum distance)
E --> F(Mark vertex as processed)
F --> G(Update distances and paths of adjacent vertices)
G --> D
D --> H(End)
H --> I(Display result)

style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f9f,stroke:#333,stroke-width:2px
style H fill:#f9f,stroke:#333,stroke-width:2px
style I fill:#f9f,stroke:#333,stroke-width:2px

Pseudocode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
Function dijkstra(n, src, dst):
// Initialize the distance, path, and known value for all vertices
For each vertex v[i] from 0 to 504:
v[i].dist = 1000000000
v[i].path = -1
v[i].known = 0

// Set the distance of the source vertex to 0
v[src].dist = 0

// The number of vertices that have been processed
cnt = 0

// The current vertex
V = 0

// The algorithm continues to run until all vertices have been processed
While cnt < n:
// Find the vertex with the minimum distance
min_dist = 1000000000
min_idx = -1

For each vertex v[i] from 0 to n-1:
// If the vertex has not been processed and its distance is less than the minimum distance
If not v[i].known and v[i].dist < min_dist:
// Update the minimum distance and index
min_dist = v[i].dist
min_idx = i

// If no more vertices can be found, break the loop
If min_idx == -1:
Break the loop

// Update the current vertex
V = min_idx

// Mark the vertex as processed
v[V].known = 1
cnt = cnt + 1

// Update the distances and paths of the adjacent vertices
For each edge e in graph[V]:
w = e.dest

If not v[w].known and v[w].dist > v[V].dist + e.length:
v[w].dist = v[V].dist + e.length
v[w].path = V

Return

backtrackPaths :Backtrack to find all shortest paths

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
graph LR
A(Start) --> B(If destination is reached)
B --> C(Add new path to list)
C --> H(End)
B --> D(Iterate through edges)
D --> E(Check distance and node visited)
E --> F(If distance and visited condition met)
F --> G(Add node to current path)
G --> D
E --> D
F --> D
D --> B
D --> H

style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f9f,stroke:#333,stroke-width:2px
style H fill:#f9f,stroke:#333,stroke-width:2px

Pseudocode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
Function backtrackPaths(src, dst, visited):
// If the destination is reached, add a new path to the list
If dst == src:
pathLists_tail++
pathLists_tail->head = NULL
pathLists_tail->next = NULL
flag = 0
Return

// Iterate through the edges of the destination node
For each edge e in graph[dst]:
prev = e.dest

// If the distance to the destination node is smaller than the previous distance and the node is not visited yet
If v[prev].dist == v[dst].dist - e.length and not visited[prev]:
// If the path list is empty and the flag is not set
If pathLists_tail->head == NULL and not flag:
// Copy the path list of the previous node
oldlist = pathLists_tail - 1
For each node in oldlist->head until node->vertex == dst:
// Add the node to the current path
addNodeToPath(node->vertex)

// Add the destination node to the current path
addNodeToPath(dst)
// If the path list is empty
Else if pathLists_tail->head == NULL:
// Add the destination node to the current path
addNodeToPath(dst)

// Mark the node as visited
visited[prev] = 1
// Add the node to the current path
addNodeToPath(prev)

// Recursively call the function with the next node as the destination
backtrackPaths(src, prev, visited)
// Unmark the node as visited
visited[prev] = 0

createPathNode:Used to create new nodes

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
graph LR
A(Start) --> B(Allocate memory for new PathNode)
B --> C(Set vertex value)
C --> D(Set next pointer to NULL)
D --> E(Return pointer to new PathNode)
E --> F(End)

style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:2px

Pseudocode

1
2
3
4
5
6
7
8
9
Function createPathNode(vertex):
// Allocate memory for a new PathNode
node = allocate memory for PathNode
// Set the vertex value of the new PathNode
node->vertex = vertex
// Set the next pointer of the new PathNode to NULL
node->next = NULL
// Return the pointer to the new PathNode
Return node

addNodeToPath:Used to add new nodes to the path

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
graph LR
A(Start) --> B(Create new node with given vertex)
B --> C(Check if tail of path list is empty)
C --> D(Set head of path list to new node)
D --> H(End)
C --> E(Set current node pointer)
E --> F(Loop through nodes until next pointer is null)
F --> G(Set current node to next node)
G --> F
F --> E
E --> I(Set next pointer of current node to new node)
I --> H

style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f9f,stroke:#333,stroke-width:2px
style H fill:#f9f,stroke:#333,stroke-width:2px
style I fill:#f9f,stroke:#333,stroke-width:2px

Pseudocode

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
Function addNodeToPath(vertex):
// Create a new node with the given vertex
newNode = createPathNode(vertex)
// If the tail of the path list is empty
If (pathLists_tail)->head is NULL:
// Set the head of the path list to the new node
(pathLists_tail)->head = newNode
// Otherwise
Else:
// Set a pointer to the current node
current = (pathLists_tail)->head
// Loop through the nodes until the next pointer is null
While current->next is not NULL:
current = current->next
// Set the next pointer of the current node to the new node
current->next = newNode

countNodesInPaths:Used to count the nodes passed on the path

sketch

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
graph LR
A(Start) --> B(Loop through each path list)
B --> C(Check if current list is not the tail)
C --> D(Set pointer to the current list)
D --> E(Loop through each node in the path list)
E --> F(Check if current node exists)
F --> G(Check if current node is not the source or destination)
G --> H(Increment count for current node)
H --> F
G --> F
F --> E
E --> C
C --> B
B --> I(End)

style A fill:#f9f,stroke:#333,stroke-width:2px
style B fill:#f9f,stroke:#333,stroke-width:2px
style C fill:#f9f,stroke:#333,stroke-width:2px
style D fill:#f9f,stroke:#333,stroke-width:2px
style E fill:#f9f,stroke:#333,stroke-width:2px
style F fill:#f9f,stroke:#333,stroke-width:2px
style G fill:#f9f,stroke:#333,stroke-width:2px
style H fill:#f9f,stroke:#333,stroke-width:2px
style I fill:#f9f,stroke:#333,stroke-width:2px

Pseudocode

1
2
3
4
5
6
7
8
9
Function countNodesInPaths(n, src, des):
// Loop through each path list
For each list in pathLists:
// Loop through each node in the path list
For each node in list:
// If the node is not the source or destination node
If node.vertex is not equal to src and node.vertex is not equal to des:
// Increment the count for the current node
cnt_onpath[node.vertex] += 1

Chapter 3: Testing Results

test case aim Expected results Actual results
10 16 2
1 2 1
1 3 1
1 4 2
2 4 1
2 5 2
3 4 1
3 0 1
4 5 1
4 6 2
5 6 1
7 3 2
7 8 1
7 0 3
8 9 1
9 0 2
0 6 2
3
1 6
7 0
5 5
Sample example given in the title, tests include the case with and without a traffic hub 2 3 4 5
None
None
2 3 4 5
None
None
5 6 2
0 1 1
0 2 2
1 3 3
2 3 1
2 4 4
3 4 2
3
0 3
0 4
1 4
Test all three with no traffic hubs None
None
None
None
None
None
20 38 4
0 1 1
0 2 1
0 3 2
1 2 1
1 4 2
1 5 3
2 3 1
2 6 3
3 4 1
3 7 2
4 5 1
4 8 3
4 9 4
5 6 2
5 10 3
6 7 1
6 11 4
7 8 2
7 12 3
8 9 1
8 13 4
9 10 2
9 14 3
10 11 1
10 15 4
11 12 2
11 16 3
12 13 1
12 17 4
13 14 2
13 18 3
14 15 1
14 19 2
15 16 3
16 17 2
16 18 3
17 19 1
18 19 2
10
0 19
1 18
2 17
3 16
4 15
5 14
6 13
7 12
8 11
9 10
Testing very complex samples 2 3 4 7 8 9 12 14
None
None
None
None
None
None
None
None
None
2 3 4 7 8 9 12 14
None
None
None
None
None
None
None
None
None

Chapter 4: Analysis and Comments

Time Complexity Analysis:

The time complexity of Dijkstra’s algorithm is O(V^2), where V is the number of vertices. In this code, an adjacency table is used to represent the graph and hence the time complexity of Dijkstra’s algorithm is O(V^2).

The process of backtracking paths involves traversing all the shortest paths, so the time complexity depends on the number of shortest paths. In the worst case, all the nodes are on the shortest paths and hence the time complexity of backtracking path is O(V).

The process of counting the number of nodes involves traversing all the nodes on the shortest path and hence the time complexity also depends on the number of shortest paths. In the worst case, all the nodes are on the shortest path and hence the time complexity of counting the number of nodes is O(V).

Therefore, the time complexity of the overall code is O(V^2).

Space complexity analysis:

The space complexity of an adjacency table is O(V + E), where V is the number of vertices and E is the number of edges. In this code, an adjacency table is used to represent the graph, so the space complexity is O(V + E).

Additional vertex structures are used to store node information, and PathNode and PathList structures to store path information. Therefore, the additional space complexity is O(V).

Therefore, the overall space complexity of the code is O(V + E).

Possible further improvements:

Optimized Search Algorithm: The time complexity of Dijkstra’s algorithm is its main bottleneck. Consider using other more efficient algorithms such as A* search (which can achieve O(b^d) when heuristic information is available, where b is the branching factor and d is the average of the heuristic functions, and is usually faster than Dijkstra’s O(V^2)), or use a priority queue (e.g., binary heap) to optimize the path search process.

Use of parallel computation: If the problem can be processed in parallel, e.g., working independently on multiple paths, consider using multithreading or multiprocessing to speed up the search.

Pruning strategies: When backtracking paths, pruning techniques can be used, such as stopping the search as soon as a shorter path is found, to avoid unnecessary computation.

Data structure optimization: If the edges of the graph are sparse and the weights of the edges are evenly distributed, you can consider using adjacency matrix instead of adjacency table, but the space complexity will be higher.

Appendix: Source Code (in C)

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
#include <stdio.h>
#include <stdlib.h>

// Initialize the counter array
int cnt_onpath[505] = {0};

// Definition of an adjacency table node that treats edges as nodes
typedef struct vertex
{
// Distance of the node from the starting node
int dist;
// The path of the node
int path;
// A flag to check if the distance of the node has been calculated
int known;
} vertex;
typedef struct Edge
{
int dest; // Target vertex
int length; // Length of the edge
struct Edge *next; // Pointer to other neighboring edges
} Edge;

// Creates a new edge and connects it to the end of the list
//Creates a new edge with a given destination and length
Edge *createEdge(int dest, int length)
{
//Allocates memory for a new edge
Edge *edge = (Edge *)malloc(sizeof(Edge));
//Sets the destination of the edge
edge->dest = dest;
//Sets the length of the edge
edge->length = length;
//Sets the next edge to NULL
edge->next = NULL;
//Returns the new edge
return edge;
}
// void dijkstra(int n, int src, int dst) is a function that calculates the shortest path between two nodes in a graph using Dijkstra's algorithm
void dijkstra(int n, int src, int dst);
// void cnt(vertex *v, int src, int dst, int n, int k) is a function that counts the number of shortest paths between two nodes in a graph
void cnt(vertex *v, int src, int dst, int n, int k);

Edge *graph[505]; // adjacency table
vertex v[505]; // Array of vertices

// A list of nodes used to store paths
// A structure to hold a path from a vertex to the next
typedef struct PathNode
{
// The vertex this pathnode leads to
int vertex;
// The next pathnode in the path
struct PathNode *next;
} PathNode;

// Used to keep a list of all paths
typedef struct PathList
{
// pointer to the first node in the list
PathNode *head;
// pointer to the next PathList in the list
struct PathList *next;
} PathList;

// Create a new path node
//This function creates a new PathNode with the specified vertex value and returns a pointer to it.
PathNode *createPathNode(int vertex)
{
//Allocate memory for a new PathNode
PathNode *node = (PathNode *)malloc(sizeof(PathNode));
//Set the vertex value of the new PathNode
node->vertex = vertex;
//Set the next pointer of the new PathNode to NULL
node->next = NULL;
//Return the pointer to the new PathNode
return node;
}
// Array to store path lists
PathList pathLists[100];
// Pointer to the head of the path list
PathList *pathLists_head = pathLists;
// Pointer to the tail of the path list
PathList *pathLists_tail = pathLists;
int desti;
// Function to add a node to the end of the path list
void addNodeToPath(int vertex)
{
// Create a new node with the given vertex
PathNode *newNode = createPathNode(vertex);
// If the tail of the path list is empty
if (!(pathLists_tail)->head)
{
// Set the head of the path list to the new node
(pathLists_tail)->head = newNode;
}
// Otherwise
else
{
// Set a pointer to the current node
PathNode *current = (pathLists_tail)->head;
// Loop through the nodes until the next pointer is null
while (current->next)
{
current = current->next;
}
// Set the next pointer of the current node to the new node
current->next = newNode;
}
}

int flag = 1;
// Backtrack from a given vertex and find all shortest paths
void backtrackPaths(int src, int dst, int *visited)
{
// If the destination is reached, add a new path to the list
if (dst == src)
{
pathLists_tail++;
pathLists_tail->head = NULL;
pathLists_tail->next = NULL;
flag = 0;
return;
}

// Iterate through the edges of the destination node
for (Edge *e = graph[dst]; e != NULL; e = e->next)
{
int prev = e->dest;
// If the distance to the destination node is smaller than the previous distance and the node is not visited yet
if (v[prev].dist == v[dst].dist - e->length && !visited[prev])
{
// If the path list is empty and the flag is not set
if (pathLists_tail->head == NULL && !flag)
{
// Copy the path list of the previous node
PathList *oldlist = pathLists_tail - 1;
for (PathNode *node = oldlist->head; node->vertex != dst; node = node->next)
{
// Add the node to the current path
addNodeToPath(node->vertex);
}
// Add the destination node to the current path
addNodeToPath(dst);
}
// If the path list is empty
else if (pathLists_tail->head == NULL)
{
// Add the destination node to the current path
addNodeToPath(dst);
}
// Mark the node as visited
visited[prev] = 1;
// Add the node to the current path
addNodeToPath(prev);

// Recursively call the function with the next node as the destination
backtrackPaths(src, prev, visited);
// Unmark the node as visited
visited[prev] = 0;
}
}
}
// Count the number of visits to nodes on all shortest paths
void countNodesInPaths(int n, int src, int des)
{
// Loop through each path list
for (PathList *list = pathLists_head; list != pathLists_tail; list++)
{
// Loop through each node in the path list
for (PathNode *node = list->head; node; node = node->next)
{
// If the node is not the source or destination node
if (node->vertex != des && node->vertex != src)
{
// Increment the count for the current node
cnt_onpath[node->vertex]++;
}
}
}
}

// Calling backtrackPaths and countNodesInPaths in the main function

int main()
{
int n, m, k;
scanf("%d %d %d", &n, &m, &k); // Enter the thresholds for the number of vertices, edges, and transportation hubs respectively
for (int i = 0; i < m; i++)
{
int len;
int src, des;
// Read the source and destination vertices, and the length of the edge.
scanf("%d", &src);
scanf("%d", &des);
scanf("%d", &len);
// Create a new edge with the given source, destination, and length.
Edge *edge = createEdge(des, len);
// Add the new edge to the existing list of edges for the source vertex.
edge->next = graph[src];
graph[src] = edge; // Add this edge to the first one in the adjacency table.
// Since this is an undirected graph, we also need to add a reverse edge
// So we create a new edge with the source and destination reversed, and add it to the list of edges for the destination vertex.
edge = createEdge(src, len);
edge->next = graph[des];
graph[des] = edge;
}
int T;
scanf("%d", &T);
int ans[505][505] = {0}; // Initialize the answer array
for (int j = 0; j < T; j++)
{
// Initialize the counter array
int src, dst;
for (int i = 0; i < 505; i++)
{
cnt_onpath[i] = 0;
}
scanf("%d %d", &src, &dst);
desti = dst;
// Used to mark if a node was visited during backtracking
int visited[505] = {0};

// Use to keep a list of all shortest paths
pathLists_tail = pathLists;
pathLists->head = createPathNode(dst);
pathLists->next = NULL;

// Call Dijkstra's algorithm
dijkstra(n, src, dst);

// Backtrack from the goal node and find all the shortest paths
backtrackPaths(src, dst, visited);
// Count the number of visits to nodes on all shortest paths
countNodesInPaths(n, src, dst);
// for each node, if the number of 1s in its binary representation is greater than or equal to k, set ans[i][j] = 1
for (int i = 0; i < n; i++)
{
if (cnt_onpath[i] >= k)
{
ans[j][i] = 1;
}
}
}
// for each test case, print the nodes that ans[i][j] is equal to 1
for (int i = 0; i < T; i++)
{
// flag is used to check if an element has been printed
int flg = 0;
// iterate through the columns of the matrix
for (int j = 0; j < n; j++)
{
// if the element exists in the matrix
if (ans[i][j])
{
// if flag is 0, print the element
if (!flg)
{
printf("%d", j);
// set flag to 1
flg = 1;
}
// otherwise, print the element with a space before it
else
{
printf(" %d", j);
}
}
}
// if flag is still 0, that means no element was printed, so print "None"
if (!flg)
{
printf("None");
}
// print a newline character
printf("\n");
}
return 0;
}
void dijkstra(int n, int src, int dst)
{
// Implement the dijkstra algorithm
// Initialize the distance, path, and known value for all vertices
for (int i = 0; i < 505; i++)
{
v[i].dist = 1000000000;
v[i].path = -1;
v[i].known = 0;
}
// Set the distance of the source vertex to 0
v[src].dist = 0;
// The number of vertices that have been processed
int cnt = 0;
// The current vertex
int V;
// The algorithm continues to run until all vertices have been processed
while (cnt < n)
{
// Find the vertex with the minimum distance
int min_dist = 1000000000;
int min_idx = -1;
for (int i = 0; i < n; i++)
{
// If the vertex has not been processed and its distance is less than the minimum distance
if (!v[i].known && v[i].dist < min_dist)
{
// Update the minimum distance and index
min_dist = v[i].dist;
min_idx = i;
}
}
// If no more vertices can be found, break the loop
if (min_idx == -1)
break;
// Update the current vertex
V = min_idx;
// Mark the vertex as processed
v[V].known = 1;
cnt++;
// Update the distances and paths of the adjacent vertices
for (Edge *e = graph[V]; e != NULL; e = e->next)
{
int w = e->dest;
if (!v[w].known && v[w].dist > v[V].dist + e->length)
{
v[w].dist = v[V].dist + e->length;
v[w].path = V;
}
}
}
return;
}

Declaration

I hereby declare that all the work done in this project titled “Transportation Hub“ is of my independent effort.