結果

問題 No.971 いたずらっ子
ユーザー qwewe
提出日時 2025-05-14 13:10:02
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 8,917 bytes
コンパイル時間 1,141 ms
コンパイル使用メモリ 106,392 KB
実行使用メモリ 348,320 KB
最終ジャッジ日時 2025-05-14 13:11:31
合計ジャッジ時間 8,059 ms
ジャッジサーバーID
(参考情報)
judge4 / judge3
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample -- * 4
other TLE * 1 -- * 20
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <string>
#include <queue>
#include <map>
#include <tuple>
#include <vector> // Ensure vector is included
#include <limits> // Required for LLONG_MAX, though not strictly needed as we initialize distances only when first reaching a state

using namespace std;

// Define long long for potentially large time values
typedef long long ll;

// Using a map to store minimum distances found so far for each state.
// The key is a tuple representing the state: {row, column, mask}.
// The value is the minimum time (distance) to reach that state.
// Using map helps manage sparse states efficiently, where many mask combinations might not be reachable for a given cell.
map<tuple<int, int, int>, ll> dists; 

// Define a min-priority queue.
// It stores pairs of {distance, state}. State is the tuple {row, column, mask}.
// We use std::greater to make it prioritize states with smaller distances.
priority_queue<pair<ll, tuple<int, int, int>>, vector<pair<ll, tuple<int, int, int>>>, greater<pair<ll, tuple<int, int, int>>>> pq;


int main() {
    // Optimize C++ standard streams for faster input/output.
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int H, W; // Grid dimensions: H rows (North-South), W columns (West-East)
    cin >> H >> W;

    vector<string> grid(H); // Stores the grid layout
    vector<pair<int, int>> k_cells; // Stores coordinates {row, col} of all initial 'k' cells (0-based index)
    // Maps a 'k' cell's coordinate pair {row, col} to a unique index from 0 to K-1.
    // This index is used for the bitmask representation.
    map<pair<int, int>, int> k_cell_indices; 

    // Read grid input and populate k_cells and k_cell_indices
    for (int i = 0; i < H; ++i) {
        cin >> grid[i];
        for (int j = 0; j < W; ++j) {
            if (grid[i][j] == 'k') {
                k_cells.push_back({i, j}); // Store coordinates
                k_cell_indices[{i, j}] = k_cells.size() - 1; // Assign index
            }
        }
    }

    int K = k_cells.size(); // Total number of initial 'k' cells

    // Create the initial mask. If there are K 'k' cells, the mask is an integer with the first K bits set to 1.
    // If K=0 (no 'k' cells), the mask is 0.
    int initial_mask = (K == 0) ? 0 : (1 << K) - 1; 

    // Set up the initial state for Dijkstra's algorithm.
    // Start at cell (0, 0) (which corresponds to problem's (1,1)), with the initial mask, and distance 0.
    tuple<int, int, int> initial_state = {0, 0, initial_mask};
    dists[initial_state] = 0; // Store distance 0 for the initial state
    pq.push({0, initial_state}); // Push initial state onto the priority queue

    // Define possible moves: South (down) and East (right).
    // dr stores row changes, dc stores column changes.
    int dr[] = {1, 0}; 
    int dc[] = {0, 1}; 

    // Dijkstra's algorithm main loop
    while (!pq.empty()) {
        // Extract the state with the smallest distance from the priority queue.
        auto top = pq.top();
        pq.pop();

        ll d = top.first; // The minimum distance found so far to reach this state
        tuple<int, int, int> current_state = top.second; // The state {row, column, mask}
        int r, c, mask;
        tie(r, c, mask) = current_state;

        // Optimization: If the extracted distance 'd' is greater than the already known shortest distance
        // to 'current_state', this means we found a shorter path earlier and already processed it (or it's currently
        // in the map with a smaller value). So, we can skip this outdated entry.
        // Uses map::find to check existence and access value without modifying map if key doesn't exist.
        auto it = dists.find(current_state);
        // Need check `it != dists.end()` primarily to handle case where state might somehow not be in map,
        // but the core check is `d > it->second`. If `d == it->second`, it's the first time we extract this state with this distance.
        if (it == dists.end() || d > it->second) {
           continue; 
        }
        
        // Check if we reached the target cell (H-1, W-1), which corresponds to (H, W) in problem statement.
        if (r == H - 1 && c == W - 1) {
            cout << d << endl; // Output the minimum time (distance)
            return 0; // Successfully found the shortest path, exit program.
        }

        // Explore neighbors by trying possible moves (South and East)
        for (int i = 0; i < 2; ++i) {
            int nr = r + dr[i]; // Calculate next row coordinate
            int nc = c + dc[i]; // Calculate next column coordinate

            // Check if the next cell (nr, nc) is within the grid boundaries
            if (nr >= 0 && nr < H && nc >= 0 && nc < W) {
                ll new_dist = d + 1; // Moving to a neighbor takes 1 minute.
                
                bool is_k = false; // Flag to indicate if the next cell is an *active* 'k' cell
                int k_idx = -1;    // Index (0..K-1) of the 'k' cell, if it is one

                // Check if the cell at (nr, nc) contains a 'k' character initially
                if (grid[nr][nc] == 'k') {
                     // Find the index associated with this 'k' cell's coordinates
                     auto k_it = k_cell_indices.find({nr, nc});
                     // Check if the coordinate pair is indeed in our map of 'k' cells
                     if(k_it != k_cell_indices.end()){ 
                         k_idx = k_it->second; // Get the index
                         // Check if the bit corresponding to this index is set (1) in the current mask.
                         // If yes, this 'k' cell is currently active.
                         if ((mask >> k_idx) & 1) { 
                            is_k = true; 
                         }
                     }
                     // Note: If k_it == k_cell_indices.end(), something is wrong with data setup. Assume it's always found.
                }

                // Based on whether the next cell is an active 'k' cell, determine the next state.
                if (is_k) {
                    // Scenario 1: Moved into an active 'k' cell.
                    // Player is teleported back to the start cell (0, 0).
                    int next_r = 0; 
                    int next_c = 0;
                    // The mask is updated: the encountered 'k' cell is deactivated.
                    // This is done by flipping the corresponding bit from 1 to 0 using XOR.
                    int next_mask = mask ^ (1 << k_idx); 
                    // Define the resulting state after teleportation and mask update.
                    tuple<int, int, int> next_state = {next_r, next_c, next_mask};

                    // Check if this path provides a shorter distance to 'next_state' than previously found.
                    auto dist_it = dists.find(next_state);
                    if (dist_it == dists.end() || new_dist < dist_it->second) {
                         // If it's the first time reaching this state, or if this path is shorter, update the distance.
                         dists[next_state] = new_dist;
                         // Push the new state and its distance onto the priority queue.
                         pq.push({new_dist, next_state});
                    }

                } else {
                    // Scenario 2: Moved into a '.' cell or a 'k' cell that was already deactivated.
                    // Player moves normally to the cell (nr, nc).
                    int next_r = nr;
                    int next_c = nc;
                    // The mask remains unchanged since no active 'k' cell was encountered.
                    int next_mask = mask; 
                    // Define the resulting state after the move.
                    tuple<int, int, int> next_state = {next_r, next_c, next_mask};

                    // Check if this path provides a shorter distance to 'next_state' than previously found.
                    auto dist_it = dists.find(next_state);
                     if (dist_it == dists.end() || new_dist < dist_it->second) {
                         // If it's the first time reaching this state, or if this path is shorter, update the distance.
                         dists[next_state] = new_dist;
                         // Push the new state and its distance onto the priority queue.
                         pq.push({new_dist, next_state});
                    }
                }
            }
        }
    }
    
    // If the priority queue becomes empty and the target was not reached,
    // this implies the target is unreachable. The problem statement guarantees
    // start and end cells are not 'k', and allows movement South/East, suggesting
    // reachability unless completely blocked. Assuming target is always reachable.
    
    return 0; // Default return code, indicates successful execution.
}
0