結果
問題 |
No.1775 Love Triangle 2
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:10:00 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
MLE
|
実行時間 | - |
コード長 | 8,431 bytes |
コンパイル時間 | 1,064 ms |
コンパイル使用メモリ | 109,988 KB |
実行使用メモリ | 766,460 KB |
最終ジャッジ日時 | 2025-05-14 13:11:27 |
合計ジャッジ時間 | 10,969 ms |
ジャッジサーバーID (参考情報) |
judge4 / judge5 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
other | AC * 4 MLE * 1 -- * 85 |
ソースコード
#include <iostream> #include <vector> #include <queue> #include <map> #include <bitset> #include <tuple> // Not strictly necessary but good practice for pair/tuple usage #include <string> // Potentially needed for bitset operations, though usually not directly #include <unordered_map> // Use unordered_map for potential speedup #include <functional> // Required for std::hash // Constants and Type Definitions const int MAXN_VAL = 100; // Maximum number of students const int MAXN_IDX = MAXN_VAL + 1; // Array size needed for 1-based indexing up to 100 const int MAX_BITS = MAXN_VAL; // The number of bits needed for the bitset Mask using Mask = std::bitset<MAX_BITS>; // Use std::bitset to represent the set of visited students // Global variables std::vector<int> non_adj[MAXN_IDX]; // Adjacency list for the complement graph (stores non-friends) bool is_friend[MAXN_IDX][MAXN_IDX]; // Matrix to check friendship status quickly int N; // Number of students int X, Y, Z; // The three special students who must be included // Custom hash function structure for std::pair<int, Mask> // This is required to use std::pair<int, Mask> as a key in std::unordered_map template <class T1, class T2> struct pair_hash { std::size_t operator() (const std::pair<T1, T2>& p) const { // Get hash value for the first element (int) auto hash1 = std::hash<T1>{}(p.first); // Get hash value for the second element (Mask/std::bitset) // std::hash<std::bitset<N>> is provided by the standard library since C++11 auto hash2 = std::hash<Mask>{}(p.second); // Combine the two hash values. // Using a method similar to boost::hash_combine to reduce collisions. // It involves XORing and bit shifts with a large prime number constant (golden ratio conjugate). size_t seed = 0; // Initialize seed for combining // Combine hash1 into seed seed ^= hash1 + 0x9e3779b9 + (seed << 6) + (seed >> 2); // Combine hash2 into seed seed ^= hash2 + 0x9e3779b9 + (seed << 6) + (seed >> 2); return seed; // A simpler alternative combination method (might have more collisions): // return hash1 ^ (hash2 << 1); } }; // Use std::unordered_map to store the shortest path length found so far for each state (vertex, mask). // The key is std::pair<int, Mask>, the value is int (path length). // Use the custom hash function `pair_hash` defined above. std::unordered_map<std::pair<int, Mask>, int, pair_hash<int, Mask>> dist; int main() { // Use fast I/O operations std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int M; // Number of friend pairs std::cin >> N >> M; // Read number of students and friend pairs std::cin >> X >> Y >> Z; // Read the IDs of the three special students // Read friend pairs and populate the is_friend matrix // Initialize is_friend to false (global bool arrays are default initialized to false) for (int i = 0; i < M; ++i) { int u, v; std::cin >> u >> v; is_friend[u][v] = true; is_friend[v][u] = true; // Friendship is symmetric } // Build the non-adjacency list (edges of the complement graph) // An edge (i, j) exists if i and j are different students and are not friends for (int i = 1; i <= N; ++i) { for (int j = 1; j <= N; ++j) { if (i != j && !is_friend[i][j]) { non_adj[i].push_back(j); } } } // Initialize the BFS queue // The queue stores pairs of (current vertex, visited mask) std::queue<std::pair<int, Mask>> q; // Create the initial mask containing only student X // We use 0-based indexing for bitset positions: student k corresponds to bit k-1 Mask initial_mask_x; initial_mask_x[X-1] = 1; // Initialize BFS starting from neighbors of X which are not friends with X // These form the first step of paths starting from X for (int neighbor : non_adj[X]) { // Create the mask for the path X -> neighbor Mask first_step_mask = initial_mask_x; first_step_mask[neighbor-1] = 1; // Mark neighbor as visited (using 0-based index) // The state is defined by the endpoint vertex (neighbor) and the set of visited vertices (mask) std::pair<int, Mask> state = {neighbor, first_step_mask}; // Store the length of the path (number of vertices) to reach this state // The path X -> neighbor involves 2 vertices. dist[state] = 2; q.push(state); // Add the initial states to the queue } int min_len_found = -1; // Stores the minimum cycle length found, initialized to -1 (meaning not found yet) // Start the Breadth-First Search while (!q.empty()) { // Get the current state from the front of the queue auto current_state = q.front(); q.pop(); int u = current_state.first; // Current vertex at the end of the path Mask current_mask = current_state.second; // Mask representing visited vertices in the path // Retrieve the length of the path leading to this state from the distance map // This lookup should be safe as the state must exist in the map if it's in the queue int current_len = dist[current_state]; // Check if we can complete a cycle by moving from the current vertex u back to the start vertex X // This is allowed only if u and X are not friends if (!is_friend[u][X]) { // If the path back to X is allowed, check if the required students Y and Z are included in the path // Use 0-based indexing for bitset checks if (current_mask[Y-1] && current_mask[Z-1]) { // If Y and Z are included, we have found a valid cycle including X, Y, Z min_len_found = current_len; // Record the length of this cycle // Since BFS explores paths layer by layer (by length), the first valid cycle found is guaranteed // to be one with the minimum possible length. We can stop the search. break; } } // Optimization: If we have already found a valid cycle, we can prune the search space. // Any path currently being explored that has a length greater than or equal to the minimum found cycle length // cannot lead to a shorter cycle. if (min_len_found != -1 && current_len >= min_len_found) { continue; // Skip exploring further from this state } // Explore neighbors 'v' of the current vertex 'u' in the non-adjacency graph for (int v : non_adj[u]) { // Check if neighbor 'v' has already been visited in the current path // Use 0-based indexing for bitset check if (current_mask[v-1]) { continue; // If v is already in the mask, skip it to avoid cycles within the path itself } // If v has not been visited, create the next state by extending the path Mask next_mask = current_mask; // Copy the current mask next_mask[v-1] = 1; // Add v to the visited set (using 0-based index) std::pair<int, Mask> next_state = {v, next_mask}; // Define the new state: endpoint v, updated mask // Check if this state {v, next_mask} has been visited before using `find()` on the distance map. // `find()` returns an iterator to the element if found, or `dist.end()` if not found. if (dist.find(next_state) == dist.end()) { // If the state has not been visited before: dist[next_state] = current_len + 1; // Record the path length (current length + 1) q.push(next_state); // Add the new state to the queue for exploration } // Note: In a standard BFS on unweighted graphs like this one, the first time a state is reached // is guaranteed to be via a shortest path (in terms of number of vertices/edges). // Therefore, we do not need to update the distance or re-queue the state if it's encountered again later. } } // After the BFS completes (either found shortest cycle or queue is empty), output the result. std::cout << min_len_found << std::endl; return 0; // Indicate successful execution }