結果

問題 No.1442 I-wate Shortest Path Problem
ユーザー qwewe
提出日時 2025-05-14 13:01:03
言語 C++17
(gcc 13.3.0 + boost 1.87.0)
結果
TLE  
実行時間 -
コード長 9,260 bytes
コンパイル時間 1,728 ms
コンパイル使用メモリ 117,648 KB
実行使用メモリ 7,840 KB
最終ジャッジ日時 2025-05-14 13:02:51
合計ジャッジ時間 8,267 ms
ジャッジサーバーID
(参考情報)
judge1 / judge5
このコードへのチャレンジ
(要ログイン)
ファイルパターン 結果
sample AC * 2
other TLE * 1 -- * 24
権限があれば一括ダウンロードができます

ソースコード

diff #

#include <iostream>
#include <vector>
#include <queue>
#include <map>
#include <tuple> // Not strictly needed now, but good practice if tuples were used
#include <vector> // Included again, harmless
#include <functional> // Potentially needed for std::hash if switching to unordered_map

using namespace std;

// Define long long type for potentially large costs
typedef long long ll;
// Define a large constant to represent infinity
const ll INF = 1e18; 

// State representation: pair<int, int>
// first element: node ID. 
//   Positive values (1 to N) represent cities.
//   Negative values (-1 to -K) represent auxiliary nodes for airlines (0 to K-1 respectively).
// second element: bitmask representing the subset of airline companies whose fees have been paid.
using State = pair<int, int>; 

// Using std::map to store distances. The key is the State, value is the minimum distance found so far.
// Map is used instead of a large array to save memory, assuming the reachable state space is sparse.
map<State, ll> dist;

// Priority queue for Dijkstra's algorithm. Stores pairs of {distance, State}.
// Uses std::greater to make it a min-priority queue.
priority_queue<pair<ll, State>, vector<pair<ll, State>>, greater<pair<ll, State>>> pq;

int main() {
    // Use fast I/O operations
    ios_base::sync_with_stdio(false);
    cin.tie(NULL);

    int N; // Number of cities
    unsigned int K; // Number of airline companies. Use unsigned int for safer bit shifts.
    cin >> N >> K;

    // Adjacency list for the railway network. Stores pairs of {neighbor_city, cost}.
    vector<vector<pair<int, int>>> adj(N + 1);
    for (int i = 0; i < N - 1; ++i) {
        int u, v, c; // Cities u, v connected by railway with cost c
        cin >> u >> v >> c;
        adj[u].push_back({v, c});
        adj[v].push_back({u, c});
    }

    // Store airline information
    vector<vector<int>> airline_cities(K); // airline_cities[i] stores list of cities served by airline i (0-indexed)
    vector<int> airline_costs(K);          // airline_costs[i] stores the cost P_i for airline i
    vector<vector<int>> city_to_airlines(N + 1); // city_to_airlines[c] stores list of airline indices (0..K-1) having an airport in city c

    for (unsigned int i = 0; i < K; ++i) { // Loop through airlines 0 to K-1
        int m; // Number of cities served by airline i
        cin >> m >> airline_costs[i]; // Read M_i and P_i
        airline_cities[i].resize(m);
        for (int j = 0; j < m; ++j) {
            cin >> airline_cities[i][j]; // Read city ID
            // Store mapping from city ID back to airline index
            // Check if city ID is valid (between 1 and N)
            if (airline_cities[i][j] >= 1 && airline_cities[i][j] <= N) {
                 city_to_airlines[airline_cities[i][j]].push_back(i);
            }
        }
    }

    int Q; // Number of queries
    cin >> Q;

    // Process each query
    for (int q = 0; q < Q; ++q) {
        int start_node, end_node; // Start and end cities for the query
        cin >> start_node >> end_node;

        // Clear data structures for the new query
        dist.clear(); 
        // Clear priority queue. Standard way is to pop elements until empty.
        while (!pq.empty()) pq.pop(); 

        // Initialize Dijkstra's algorithm
        State initial_state = {start_node, 0}; // Start at city `start_node` with no airlines paid (mask 0)
        dist[initial_state] = 0; // Distance to initial state is 0
        pq.push({0, initial_state}); // Push initial state into priority queue

        // Run Dijkstra's algorithm
        while (!pq.empty()) {
            // Extract state with minimum distance
            // C++17 structured binding: `auto [d, current_state] = ...`
             ll d;
             State current_state;
             tie(d, current_state) = pq.top(); // alternative for C++11/14
            // auto [d, current_state] = pq.top(); // C++17
            pq.pop();
            
            int u = current_state.first; // Current node ID (city or aux)
            int mask = current_state.second; // Current mask

            // Check if we found a shorter path to this state already. If so, skip processing.
            // Use find() then check iterator and value. Using operator[] directly on map could insert default element.
             auto it = dist.find(current_state);
             // This check is essential for correctness and efficiency.
             // If state isn't in dist map or the stored distance is already smaller, skip.
             if (it == dist.end() || it->second < d) {
                 continue;
             }

            // Process transitions based on node type (city or auxiliary)
            if (u > 0) { // Current node is a city (ID > 0)
                
                // 1. Railway transitions: Move to adjacent city v with cost c
                for (auto& edge : adj[u]) {
                    int v = edge.first;
                    int cost = edge.second;
                    State next_state = {v, mask}; // Destination city v, same airline mask
                    ll new_dist = d + cost; // New total distance
                    
                    // Update distance if this path is shorter
                    auto next_it = dist.find(next_state);
                    if (next_it == dist.end() || new_dist < next_it->second) {
                        dist[next_state] = new_dist;
                        pq.push({new_dist, next_state});
                    }
                }

                // 2. Airline initiation transitions: Pay for an airline if not already paid
                for (int airline_idx : city_to_airlines[u]) {
                    // Check if the airline_idx bit is NOT set in the mask
                    if (!((mask >> airline_idx) & 1)) { 
                        int p = airline_costs[airline_idx]; // Cost to pay for this airline
                        // New state: same city u, updated mask with airline_idx bit set
                        State next_state = {u, mask | (1 << airline_idx)}; 
                        ll new_dist = d + p; // New total distance includes airline fee

                        // Update distance if this path is shorter
                        auto next_it = dist.find(next_state);
                        if (next_it == dist.end() || new_dist < next_it->second) {
                            dist[next_state] = new_dist;
                            pq.push({new_dist, next_state});
                        }
                    }
                }
                
                // 3. Transition to auxiliary node: If airline is paid, move to its aux node (cost 0)
                for (int airline_idx : city_to_airlines[u]) {
                     // Check if the airline_idx bit IS set in the mask
                    if (((mask >> airline_idx) & 1)) { 
                         // Map airline index `airline_idx` (0..K-1) to negative ID `-(airline_idx + 1)` (-1..-K)
                         State aux_state = {-(airline_idx + 1), mask}; 
                         ll new_dist = d; // Cost 0 transition

                         // Update distance if this path is shorter
                         auto next_it = dist.find(aux_state);
                         if (next_it == dist.end() || new_dist < next_it->second) {
                            dist[aux_state] = new_dist;
                            pq.push({new_dist, aux_state});
                         }
                    }
                }

            } 
            else { // Current node is an auxiliary node (ID < 0)
                int airline_idx = -u - 1; // Retrieve 0-based airline index from negative ID
                ll current_dist = d; // Distance to the auxiliary node
                
                 // Transition from auxiliary node back to all cities served by this airline (cost 0)
                 for (int v : airline_cities[airline_idx]) {
                     State city_state = {v, mask}; // Target city v, same mask
                     ll new_dist = current_dist; // Cost 0 transition

                     // Update distance if this path is shorter
                     auto next_it = dist.find(city_state);
                     if (next_it == dist.end() || new_dist < next_it->second) {
                         dist[city_state] = new_dist;
                         pq.push({new_dist, city_state});
                     }
                 }
            }
        }
        
        // After Dijkstra finishes, find the minimum cost to reach the destination city `end_node`
        // across all possible final airline masks.
        ll final_min_cost = INF;
        // Iterate through all possible masks from 0 to 2^K - 1
        for (unsigned int final_mask = 0; final_mask < (1u << K); ++final_mask) {
             State final_state = {end_node, (int)final_mask}; // State at destination city with this mask
             auto it = dist.find(final_state); // Check if this state was reached
             if (it != dist.end()) {
                 final_min_cost = min(final_min_cost, it->second); // Update minimum cost if smaller
             }
         }

        // Output the minimum cost for the query
        cout << final_min_cost << "\n";
    }

    return 0;
}
0