Orig Description
G: DAG Trio / DAG Trio
This problem is the same setting as D: DAG Trio (Easy) except for the constraints.
Prologue
My little brother has been muttering "dag torio" recently.
Worried, I looked it up and found that in his class, $k$-DAG (a directed graph in which removing $k$ edges makes the number of connected components $k$, and all of them are DAG) is popular, and 3-DAG is called DAG trio.
To be respected by my brother, I decided to make a program that determines whether a given graph is DAG trio or not.
Problem Statement
Given a directed graph with $N$ vertices and $M$ edges.
Each vertex is numbered from $1$ to $N$.
Each directed edge is numbered from $1$ to $M$.
Directed edge $i$ goes from vertex $a_i$ to vertex $b_i$.
The graph is connected and simple (there is a path between any two vertices when ignoring the direction of edges, and there are no self-loops or multiple edges).
If the given graph is DAG trio, output "YES", otherwise output "NO".
Input
$N \ M$
$a_1 \ b_1$
$a_2 \ b_2$
$\vdots$
$a_M \ b_M$
Constraints
$3 \le N \le 500$
$\max(3, N−1) \le M \le 30000$
$1 \le a_i, b_i \le N$
The graph is connected when ignoring the direction of edges.
$a_i \neq b_i$ for all $i$.
$\{a_i, b_i\} \neq \{a_j, b_j\}$ for all $i \neq j$.
Output
Output "YES" or "NO" in a single line.
Sample
Sample Input 1
3 3
1 2
2 3
3 1
Sample Output 1
YES
Sample Input 2
6 7
1 2
2 3
4 3
4 5
5 6
6 4
3 6
Sample Output 2
YES
Sample Input 3
7 10
4 2
4 7
4 6
2 7
2 5
2 1
5 6
1 3
6 3
4 3
Sample Output 3
NO
Sample Input 4
4 4
1 2
3 2
4 3
2 4
Sample Output 4
YES
Sample Input 5
8 9
5 1
3 8
1 2
4 8
4 7
7 5
6 5
3 2
4 2
Sample Output 5
YES
Extracted Specification
An integer N (3 ≤ N ≤ 500), representing some quantity or size.
An integer M (max(3, N−1) ≤ M ≤ 30000), representing some quantity or size.
M pairs of integers (a_i, b_i), where 1 ≤ a_i, b_i ≤ N and a_i ≠ b_i.
### Example Input:
```
3 3
1 2
2 3
3 1
```
### Function Signature:
Write a function f(N, M, edges) that takes in the input.
def f(N: int, M: int, edges: List[Tuple[int, int]]):
'''
N: an integer
M: an integer
edges: a list of tuples of integers
'''
Test Case Generator
To generate test cases for the problem "DAG Trio," we need to create a random connected directed graph with the given constraints. Here is a Python function to generate test cases for this problem:
```python
import random
from collections import defaultdict
def generate_connected_graph(N, M):
# Generate a connected graph using a variation of the Kruskal's algorithm
# Initialize parent and rank for union-find
parent = list(range(N))
rank = [0] * N
def find(x):
if parent[x] != x:
parent[x] = find(parent[x])
return parent[x]
def union(x, y):
rootX = find(x)
rootY = find(y)
if rootX != rootY:
if rank[rootX] > rank[rootY]:
parent[rootY] = rootX
elif rank[rootX] < rank[rootY]:
parent[rootX] = rootY
else:
parent[rootY] = rootX
rank[rootX] += 1
edges = set()
while len(edges) < M:
# Randomly select two different vertices
u, v = random.sample(range(1, N + 1), 2)
if (u, v) not in edges and (v, u) not in edges:
edges.add((u, v))
union(u - 1, v - 1)
return list(edges)
def tcgen():
N = random.randint(3, 500)
M = random.randint(max(3, N - 1), 30000)
edges = generate_connected_graph(N, M)
# Ensure that the graph is connected
while not is_connected(N, edges):
edges = generate_connected_graph(N, M)
return N, M, edges
def is_connected(N, edges):
# Check if the graph is connected using BFS/DFS
adj_list = defaultdict(list)
for u, v in edges:
adj_list[u].append(v)
adj_list[v].append(u)
visited = set()
def dfs(node):
stack = [node]
while stack:
current = stack.pop()
if current not in visited:
visited.add(current)
stack.extend(adj_list[current])
# Start DFS from node 1
dfs(1)
return len(visited) == N
# Example of generating a test case
if __name__ == "__main__":
N, M, edges = tcgen()
print(N, M)
for edge in edges:
print(edge[0], edge[1])
```
### Explanation:
1. **Graph Generation**: The `generate_connected_graph` function generates a connected graph using a variation of Kruskal's algorithm. It ensures the graph is connected by using a union-find data structure to guarantee that all vertices are in the same connected component.
2. **Graph Validation**: The `is_connected` function checks if the graph is connected using DFS. It ensures that all vertices are reachable from any starting vertex.
3. **Main Function**: The `tcgen` function generates random values for \(N\) and \(M\) within the given constraints and ensures that the generated graph is connected by re-generating it until it meets the connectivity criteria.
4. **Test Case Output**: The generated test case includes the number of vertices \(N\), the number of edges \(M\), and the list of edges.
This generator ensures that the graph is connected and adheres to the problem constraints, producing valid and varied test cases for the "DAG Trio" problem.
Extract Arguments
def extract_arguments(fh):
N, M = map(int, fh.readline().strip().split())
edges = []
for _ in range(M):
a, b = map(int, fh.readline().strip().split())
edges.append((a, b))
return N, M, edges