Flight Routes Check
Explicación
El teorema que se usa aquí es que si un vértice puede tanto alcanzar como ser alcanzado por todos los demás, entonces todo vértice de este grafo puede alcanzar a todos los demás.
Digamos que es verdadero si se puede ir del vértice al vértice a través de una serie de aristas. Además, definamos el grafo dirigido dado en el enunciado como y su reverso (donde una arista se convierte en ) como . Entonces, si para tanto en como en , la respuesta es “YES”.
Para computar , podemos ejecutar un DFS desde el vértice y comprobar si se puede alcanzar el vértice para todo . Si no podemos, entonces imprimimos si estamos ejecutando el DFS en y en caso contrario.
Demostración
Hagamos una demostración por contradicción. Supongamos que es verdadero para todos los vértices tanto en como en , y existe un par de vértices tal que . Como es verdadero en , entonces debe ser verdadero en . Además, debe ser verdadero en . Así, se puede viajar de , lo que contradice que . Por lo tanto, es verdadero para todos los vértices .
Implementación
Complejidad temporal:
#include <bits/stdc++.h>
using namespace std;
void dfs(int pos, vector<vector<int>> &flights, vector<bool> &visited) {
for (int c : flights[pos]) {
if (visited[c]) continue;
visited[c] = true;
dfs(c, flights, visited);
}
}
int main() {
int n, m;
cin >> n >> m;
vector<vector<int>> forward_graph(n);
vector<vector<int>> reverse_graph(n);
for (int i = 0; i < m; i++) {
int a, b;
cin >> a >> b;
a--;
b--;
forward_graph[a].push_back(b);
reverse_graph[b].push_back(a);
}
// Forward Pass
vector<bool> visited(n);
dfs(0, forward_graph, visited);
for (int i = 1; i < n; i++) {
if (visited[i] == false) {
cout << "NO\n";
cout << 1 << " " << i + 1 << "\n";
return 0;
}
}
// Reverse Pass
visited = vector<bool>(n, false);
dfs(0, reverse_graph, visited);
for (int i = 1; i < n; i++) {
if (visited[i] == false) {
cout << "NO" << endl;
cout << i + 1 << " " << 1 << "\n";
return 0;
}
}
cout << "YES" << endl;
}import java.io.*;
import java.util.*;
public class FlightRoutesCheck {
static int n, m;
static boolean[] vis;
public static void main(String[] args) {
Kattio io = new Kattio();
n = io.nextInt();
m = io.nextInt();
// Stores the graph we are given (or G)
ArrayList<ArrayList<Integer>> adj1 = new ArrayList<>();
// Stores the reverse of the graph we are given (or G')
ArrayList<ArrayList<Integer>> adj2 = new ArrayList<>();
for (int i = 0; i < n; i++) {
adj1.add(new ArrayList<>());
adj2.add(new ArrayList<>());
}
for (int i = 0; i < m; i++) {
int a = io.nextInt() - 1;
int b = io.nextInt() - 1;
adj1.get(a).add(b);
adj2.get(b).add(a);
}
// Run dfs to check if you can reach all other vertices from vertex 1
vis = new boolean[n];
dfs(0, adj1);
for (int i = 0; i < n; i++) {
// If some vertex wasn't visited, that means that we cannot reach
// all other vertices, so we return NO
if (!vis[i]) {
io.println("NO");
io.println(1 + " " + (i + 1));
io.close();
return;
}
}
// Run dfs to check if you can reach vertex 1 from all other vertices
vis = new boolean[n];
dfs(0, adj2);
for (int i = 0; i < n; i++) {
// If some vertex wasn't visited, that means vertex 1 cannot be
// reached from all other vertices, so we return NO
if (!vis[i]) {
io.println("NO");
io.println((i + 1) + " " + 1);
io.close();
return;
}
}
// If we haven't exited yet, that means the answer is YES
io.println("YES");
io.close();
}
static void dfs(int v, ArrayList<ArrayList<Integer>> adj) {
vis[v] = true;
for (int to : adj.get(v)) {
if (!vis[to]) { dfs(to, adj); }
}
}
// CodeSnip{Kattio}
}from typing import List, Set
n, m = map(int, input().split())
forward_graph = [[] for _ in range(n)]
reverse_graph = [[] for _ in range(n)]
for _ in range(m):
a, b = map(int, input().split())
forward_graph[a - 1].append(b - 1)
reverse_graph[b - 1].append(a - 1)
def dfs(graph: List[List[int]]) -> Set[int]:
"""
Performs a depth-first traversal of a graph starting from node 0. Removes
each node reached from a set of all nodes. Once complete, the set will only
contain unvisited nodes and is then returned.
:param graph: An adjacency list representing a graph.
:return: A set containing all unvisited nodes in the depth-first traversal.
"""
unvisited = set(range(1, n))
stack = [0]
while stack:
curr = stack.pop()
for adj in graph[curr]:
if adj in unvisited:
stack.append(adj)
unvisited.remove(adj)
return unvisited
# These will be empty if there are no unvisited nodes
unvisited_fwd = dfs(forward_graph)
unvisited_rev = dfs(reverse_graph)
if unvisited_fwd:
print("NO")
print(f"1 {unvisited_fwd.pop() + 1}")
elif unvisited_rev:
print("NO")
print(f"{unvisited_rev.pop() + 1} 1")
else:
print("YES")El problema también se puede resolver usando componentes fuertemente conexas (SCC).