結果
| 問題 | No.1775 Love Triangle 2 |
| コンテスト | |
| ユーザー |
qwewe
|
| 提出日時 | 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
}
qwewe