結果

問題 No.340 雪の足跡
ユーザー qwewe
提出日時 2025-05-14 12:59:50
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 9,997 bytes
コンパイル時間 1,062 ms
コンパイル使用メモリ 89,440 KB
実行使用メモリ 7,844 KB
最終ジャッジ日時 2025-05-14 13:01:28
合計ジャッジ時間 5,130 ms
ジャッジサーバーID
(参考情報)
judge3 / judge2
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 5
other AC * 15 TLE * 1 -- * 16
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <queue>
#include <utility> // Required for std::pair, though not directly used, good practice
#include <algorithm> // Required for std::min and std::max

using namespace std;

// Use int for distance. The maximum possible distance W*H-1 can be up to 10^6 - 1,
// which fits comfortably within a 32-bit signed integer.
const int INF = -1; // Use -1 to represent infinity or unreachable state.

int main() {
    // Optimize C++ standard streams for faster I/O. Crucial for performance-sensitive problems.
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int W, H; // Grid dimensions: Width W, Height H
    cin >> W >> H;
    
    int N; // Number of adults
    cin >> N; 

    // Handle the edge case where the grid is 1x1.
    // In this case, Mana's home (cell 0) is the same as Mitsuru's home (cell W*H-1 = 0).
    // The distance is 0. We must still read the rest of the input to avoid errors.
    if (W == 1 && H == 1) {
        // Consume the remaining input lines describing adult paths.
        for(int i = 0; i < N; ++i) {
            int M; // Number of stops for adult i
            cin >> M;
            int dummy; // Variable to read and discard cell indices
            // An adult i's path involves M+1 points: B_i,0 (start) to B_i,M (last stop).
            for(int j = 0; j <= M; ++j) {
                 cin >> dummy; // Read and discard each B_i,j
            }
        }
        cout << 0 << endl; // Output the distance 0
        return 0; // Exit program
    }

    // Calculate the total number of cells in the grid. Use long long to prevent potential overflow if W*H is large, although W*H <= 10^6 fits in int.
    long long total_cells = (long long)W * H;
    
    // Data structures to store traversability of edges between adjacent cells.
    // `can_pass_horizontal[h][w]` is true if Mana can pass between cell (w, h) and cell (w+1, h).
    // Dimensions are H rows by (W-1) columns. Handle W=1 case by creating a vector of size 0.
    vector<vector<bool>> can_pass_horizontal(H, vector<bool>(W > 1 ? W - 1 : 0, false)); 
    
    // `can_pass_vertical[h][w]` is true if Mana can pass between cell (w, h) and cell (w, h+1).
    // Dimensions are (H-1) rows by W columns. Handle H=1 case by creating a vector of size 0.
    vector<vector<bool>> can_pass_vertical(H > 1 ? H - 1 : 0, vector<bool>(W, false));

    // Process each adult's path to mark the edges they traverse as traversable for Mana.
    for (int i = 0; i < N; ++i) {
        int M; // Number of stops for adult i
        cin >> M;
        
        int prev_B; // Cell index where the adult was previously located
        cin >> prev_B; // Read the starting cell B_i,0 for adult i

        // An adult path consists of M segments: B_i,j -> B_i,j+1 for j=0..M-1
        for (int j = 0; j < M; ++j) {
            int curr_B; // Cell index where the adult stops next
            cin >> curr_B; // Read the next stop B_i, j+1
            
            // Convert cell indices to (w, h) coordinates
            int prev_w = prev_B % W; // Previous column
            int prev_h = prev_B / W; // Previous row
            int curr_w = curr_B % W; // Current column
            int curr_h = curr_B / W; // Current row

            // Check if the move is vertical (same column)
            if (prev_w == curr_w) { 
                // Only process vertical moves if H > 1 (grid has vertical dimension)
                if (H > 1) {
                    int h_start = min(prev_h, curr_h); // Starting row index for the segment
                    int h_end = max(prev_h, curr_h);   // Ending row index for the segment
                    // Mark all vertical edges along the path segment as traversable.
                    // The edge between (prev_w, h) and (prev_w, h+1) corresponds to can_pass_vertical[h][prev_w].
                    for (int h = h_start; h < h_end; ++h) {
                        // Basic boundary check for safety, though problem constraints should guarantee valid indices.
                        if (h >= 0 && h < H - 1 && prev_w >= 0 && prev_w < W) { 
                             can_pass_vertical[h][prev_w] = true;
                        }
                    }
                }
            // Otherwise, the move must be horizontal (guaranteed by problem constraints)
            } else { 
                // Only process horizontal moves if W > 1 (grid has horizontal dimension)
                if (W > 1) {
                    int w_start = min(prev_w, curr_w); // Starting column index for the segment
                    int w_end = max(prev_w, curr_w);   // Ending column index for the segment
                    // Mark all horizontal edges along the path segment as traversable.
                    // The edge between (w, prev_h) and (w+1, prev_h) corresponds to can_pass_horizontal[prev_h][w].
                    for (int w = w_start; w < w_end; ++w) {
                        // Basic boundary check for safety.
                       if (prev_h >= 0 && prev_h < H && w >= 0 && w < W - 1) { 
                            can_pass_horizontal[prev_h][w] = true;
                       }
                    }
                }
            }
            prev_B = curr_B; // Update the previous location for the next segment calculation
        }
    }

    // Perform Breadth-First Search (BFS) to find the shortest path from cell 0 to cell W*H-1.
    vector<int> dist(total_cells, INF); // Stores the shortest distance from cell 0 to each cell. Initialize with INF (-1).
    queue<int> q; // Queue for BFS traversal. Stores cell indices.

    // Start BFS from cell 0 (Mana's home) if the grid has cells.
    if (total_cells > 0) { 
        dist[0] = 0; // Distance to starting cell is 0
        q.push(0);   // Add starting cell to the queue
    }

    int final_dist = INF; // Variable to store the shortest distance found to the destination.

    // BFS main loop
    while (!q.empty()) {
        int u_idx = q.front(); // Get the current cell index from the front of the queue
        q.pop();              // Remove it from the queue

        // Check if we have reached the destination cell (Mitsuru's home at index W*H - 1)
        if (u_idx == total_cells - 1) {
            final_dist = dist[u_idx]; // Store the distance found
            break; // Found the shortest path, exit BFS loop
        }

        // Get coordinates of the current cell
        int u_w = u_idx % W;
        int u_h = u_idx / W;

        // Explore neighbors using the marked passages
        
        // Check North neighbor: (u_w, u_h + 1)
        // Requires H > 1 to have a North neighbor and possibility of vertical passages.
        if (H > 1 && u_h + 1 < H) { // Check boundary: Is there a cell to the North?
            // Check passage: Is vertical passage between (u_w, u_h) and (u_w, u_h+1) allowed?
            // Passage information is stored at can_pass_vertical[u_h][u_w].
            if (can_pass_vertical[u_h][u_w]) { 
                 int v_idx = u_w + (u_h + 1) * W; // Calculate index of the North neighbor
                 if (dist[v_idx] == INF) { // If neighbor has not been visited yet
                     dist[v_idx] = dist[u_idx] + 1; // Update distance
                     q.push(v_idx);                 // Add neighbor to the queue
                 }
            }
        }
        
        // Check South neighbor: (u_w, u_h - 1)
        // Requires H > 1 for South neighbor / vertical passages.
        if (H > 1 && u_h - 1 >= 0) { // Check boundary: Is there a cell to the South?
            // Check passage: Is vertical passage between (u_w, u_h-1) and (u_w, u_h) allowed?
            // Passage information is stored at can_pass_vertical[u_h - 1][u_w].
             if (can_pass_vertical[u_h - 1][u_w]) {
                 int v_idx = u_w + (u_h - 1) * W; // Calculate index of the South neighbor
                 if (dist[v_idx] == INF) { // If neighbor not visited
                     dist[v_idx] = dist[u_idx] + 1;
                     q.push(v_idx);
                 }
             }
        }
        
        // Check East neighbor: (u_w + 1, u_h)
        // Requires W > 1 for East neighbor / horizontal passages.
        if (W > 1 && u_w + 1 < W) { // Check boundary: Is there a cell to the East?
             // Check passage: Is horizontal passage between (u_w, u_h) and (u_w+1, u_h) allowed?
             // Passage information is stored at can_pass_horizontal[u_h][u_w].
            if (can_pass_horizontal[u_h][u_w]) {
                int v_idx = (u_w + 1) + u_h * W; // Calculate index of the East neighbor
                 if (dist[v_idx] == INF) { // If neighbor not visited
                     dist[v_idx] = dist[u_idx] + 1;
                     q.push(v_idx);
                 }
            }
        }
        
        // Check West neighbor: (u_w - 1, u_h)
        // Requires W > 1 for West neighbor / horizontal passages.
        if (W > 1 && u_w - 1 >= 0) { // Check boundary: Is there a cell to the West?
             // Check passage: Is horizontal passage between (u_w-1, u_h) and (u_w, u_h) allowed?
             // Passage information is stored at can_pass_horizontal[u_h][u_w - 1].
             if (can_pass_horizontal[u_h][u_w - 1]) {
                 int v_idx = (u_w - 1) + u_h * W; // Calculate index of the West neighbor
                 if (dist[v_idx] == INF) { // If neighbor not visited
                     dist[v_idx] = dist[u_idx] + 1;
                     q.push(v_idx);
                 }
             }
        }
    }

    // Output the final result based on whether the destination was reached.
    if (final_dist != INF) {
        cout << final_dist << endl; // Output the shortest distance found
    } else {
         // If destination is unreachable (and W*H > 1, because the W=1 H=1 case was handled earlier)
         cout << "Odekakedekinai.." << endl; // Output the "cannot go out" message
    }

    return 0; // Indicate successful execution
}
0