結果

問題 No.1023 Cyclic Tour
ユーザー qwewe
提出日時 2025-05-14 12:59:48
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
WA  
実行時間 -
コード長 7,909 bytes
コンパイル時間 774 ms
コンパイル使用メモリ 81,300 KB
実行使用メモリ 14,208 KB
最終ジャッジ日時 2025-05-14 13:00:58
合計ジャッジ時間 7,953 ms
ジャッジサーバーID
(参考情報)
judge3 / judge4
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 4
other AC * 44 WA * 5
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <utility> // For std::pair

using namespace std;

// Global variables
// Adjacency list representation of the graph.
// Each element adj[u] is a vector of pairs {v, road_idx}, meaning there's a directed edge from u to v using road with index road_idx.
vector<vector<pair<int, int>>> adj; 
// Stores the type of each road. road_type[i] = 1 if road i is bidirectional, 2 if unidirectional.
vector<int> road_type; 
// Tracks the state of each vertex during DFS. 
// 0: white (not visited yet)
// 1: gray (currently visiting, on the recursion stack)
// 2: black (finished visiting this node and all its descendants)
vector<int> visited; 

/**
 * @brief Performs Depth First Search (DFS) to detect cycles in the directed graph.
 * 
 * This DFS implementation specifically handles the problem constraint:
 * A cycle formed by immediately traversing a bidirectional road back and forth 
 * (e.g., u -> v -> u using the same bidirectional road i for both steps) is considered invalid.
 * Such a traversal is disallowed because it uses the same "road" twice.
 * 
 * @param u The current vertex being visited.
 * @param incoming_road_idx The index of the road used to arrive at vertex u from its parent in the DFS tree.
 *                          This is crucial for detecting and correctly handling the forbidden length-2 cycles.
 *                          For the initial starting node of a DFS traversal, this value is -1.
 * @return true if a valid cycle (according to the problem rules) is detected starting from or passing through u, false otherwise.
 */
bool dfs(int u, int incoming_road_idx) {
    // Mark the current vertex u as gray, indicating it's currently being visited (on the recursion stack).
    visited[u] = 1; 

    // Iterate through all outgoing edges from vertex u.
    for (auto& edge : adj[u]) {
        int v = edge.first; // The neighbor vertex connected by the current edge.
        int current_road_idx = edge.second; // The index of the road corresponding to the edge (u, v).

        // Check the state of the neighbor vertex v.
        if (visited[v] == 1) { // Case 1: The edge leads to a gray node v.
            // A gray node is currently on the recursion stack, meaning it's an ancestor of u in the DFS tree.
            // This indicates that we have found a back edge, which completes a cycle.
            
            // Now, we must check if this cycle is the specific forbidden type:
            // A length-2 cycle u -> v -> u using the same bidirectional road for both steps.
            // This condition holds if:
            // 1. The current road (u -> v) `current_road_idx` is bidirectional (road_type == 1).
            // 2. This road index `current_road_idx` is the same as the road index `incoming_road_idx` 
            //    which was used to travel from v to u to reach the current node u.
            
            // Check if road_type vector access is valid. road indices are 1..M. Vector indices are 0..M.
            // Since current_road_idx comes from input (1 to M), access road_type[current_road_idx] is safe.
            if (road_type[current_road_idx] == 1 && current_road_idx == incoming_road_idx) {
                 // This is exactly the forbidden cycle configuration.
                 // We should ignore this path and continue exploring other neighbors of u.
                 continue; 
            } else {
                // We have found a valid cycle. This cycle is either:
                // - Longer than length 2.
                // - Length 2 (u -> v -> u), but valid because:
                //   - At least one of the edges (u, v) or (v, u) uses a unidirectional road.
                //   - Both edges use bidirectional roads, but they are different roads (different indices).
                // In any case, a valid cycle exists. We can report true and terminate the search.
                return true;
            }
        } else if (visited[v] == 0) { // Case 2: The edge leads to a white node v.
            // A white node has not been visited yet in this DFS traversal.
            // We explore this node recursively.
            // We pass `current_road_idx` as the `incoming_road_idx` for the recursive call on v,
            // because this is the road used to reach v from u.
            if (dfs(v, current_road_idx)) {
                // If the recursive call `dfs(v, ...)` returns true, it means a cycle was found
                // somewhere down the path starting from v. We propagate this finding back up.
                return true; 
            }
        }
        // Case 3: visited[v] == 2. The edge leads to a black node v.
        // A black node has been fully explored previously (either in the current DFS traversal or a prior one).
        // An edge to a black node signifies a cross edge or forward edge in the DFS tree structure.
        // Such edges do not form *new* cycles involving the current path back to an ancestor (gray node).
        // Therefore, we simply ignore this edge for the purpose of finding cycles involving the current path.
    }

    // After exploring all neighbors of u, if no cycle was found involving u through back edges,
    // mark u as black, indicating that the visit to u and its descendants is complete.
    visited[u] = 2; 
    // Return false, indicating no cycle was found originating from or passing through u along the paths explored from this DFS call.
    return false; 
}

int main() {
    // Use faster I/O operations standard in competitive programming.
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N; // Number of cities (vertices)
    int M; // Number of roads (original edges)
    cin >> N >> M;

    // Initialize data structures. We use size N+1 and M+1 to allow for 1-based indexing used in the problem statement.
    adj.resize(N + 1); 
    road_type.resize(M + 1); 
    visited.resize(N + 1, 0); // Initialize all nodes as unvisited (white).

    // Read road information and build the directed graph representation using an adjacency list.
    for (int i = 1; i <= M; ++i) {
        int u, v, c; // Read vertices u, v connected by road i, and road type c.
        cin >> u >> v >> c;
        road_type[i] = c; // Store the type of road i (1 for bidirectional, 2 for unidirectional).
        
        if (c == 1) {
            // If road i is bidirectional, it allows travel in both directions.
            // Add a directed edge from u to v associated with road index i.
            adj[u].push_back({v, i});
            // Add a directed edge from v to u associated with the same road index i.
            adj[v].push_back({u, i});
        } else { // c == 2
            // If road i is unidirectional, it allows travel only from u to v.
            // Add a directed edge from u to v associated with road index i.
            adj[u].push_back({v, i});
        }
    }

    bool cycle_found = false;
    // Iterate through all vertices from 1 to N.
    // This loop ensures that we initiate DFS from each unvisited node,
    // covering all potentially disconnected components of the graph.
    for (int i = 1; i <= N; ++i) {
        // If vertex i has not been visited yet (is white).
        if (visited[i] == 0) { 
            // Start a new DFS traversal from vertex i.
            // The initial call from the main loop doesn't have an incoming edge, so `incoming_road_idx` is -1.
            if (dfs(i, -1)) { 
                // If the DFS call returns true, it means a valid cycle was found.
                cycle_found = true;
                // Since we only need to determine if *any* valid cycle exists, we can stop searching.
                break; 
            }
        }
    }

    // Print the final result based on whether a cycle was found.
    if (cycle_found) {
        cout << "Yes" << endl;
    } else {
        cout << "No" << endl;
    }

    return 0;
}
0