結果
問題 |
No.912 赤黒木
|
ユーザー |
![]() |
提出日時 | 2025-05-14 13:14:07 |
言語 | C++17 (gcc 13.3.0 + boost 1.87.0) |
結果 |
WA
|
実行時間 | - |
コード長 | 8,355 bytes |
コンパイル時間 | 1,065 ms |
コンパイル使用メモリ | 88,240 KB |
実行使用メモリ | 43,860 KB |
最終ジャッジ日時 | 2025-05-14 13:15:21 |
合計ジャッジ時間 | 7,570 ms |
ジャッジサーバーID (参考情報) |
judge5 / judge1 |
(要ログイン)
ファイルパターン | 結果 |
---|---|
sample | AC * 2 |
other | AC * 10 WA * 20 |
ソースコード
#include <iostream> #include <vector> #include <numeric> #include <algorithm> // Use vectors for adjacency lists std::vector<std::vector<int>> adj_R; // Adjacency list for the Red Tree T_R // No need to store the adjacency list for the Black Tree T_B fully, only degrees are needed. std::vector<std::vector<int>> adj_G_prime; // Adjacency list for the forest G' formed by the required red edges/paths // Store degrees for vertices based on black edges std::vector<int> degree_B; // Flag for vertices with odd degree in the black graph (identifies the set O_B) std::vector<bool> is_odd_B; // Stores the count of O_B vertices in the subtree rooted at each node in T_R during DFS std::vector<int> subtree_odd_count; // Visited flags for the second DFS traversal on G' (the forest) std::vector<bool> visited; // C(O_B): The cost of the minimum weight perfect matching on the set O_B. // This is computed as the sum of weights (which are 1 for each edge) of red edges // that are part of the paths connecting matched pairs in O_B. long long C_OB = 0; // max_path_len: The maximum length among all paths in the forest G'. // This corresponds to the maximum weight edge in the minimum weight perfect matching M on O_B. int max_path_len = 0; /** * @brief First DFS on the Red Tree (T_R). * Computes the size of O_B within each subtree. * Calculates the total cost C(O_B) based on subtree counts. * Builds the adjacency list for the forest G' which represents the paths of the matching. * * @param u Current node being visited. * @param p Parent node in the DFS traversal (to avoid going back up). */ void dfs1(int u, int p) { // Initialize the count of odd-degree (in T_B) vertices in the subtree rooted at u. // Starts with 1 if u itself is in O_B, otherwise 0. subtree_odd_count[u] = is_odd_B[u]; // Iterate through all neighbors of u in the Red Tree T_R. for (int v : adj_R[u]) { // Skip the parent node to prevent infinite loops in the undirected graph. if (v == p) continue; // Recursively call dfs1 for the child node v. dfs1(v, u); // Accumulate the count from the child's subtree into the current node's count. subtree_odd_count[u] += subtree_odd_count[v]; } // After visiting all children, consider the edge connecting u to its parent p. // This check determines if the edge (p, u) is part of the red paths needed for the matching. // The condition `p != 0` ensures we don't process a dummy edge for the root node (node 1). // `subtree_odd_count[u] % 2 != 0` checks if the subtree rooted at u contains an odd number of O_B vertices. // If true, the edge (p, u) must be traversed by exactly one path in the minimum cost matching. if (p != 0 && subtree_odd_count[u] % 2 != 0) { // Increment the total cost C(O_B) because this edge contributes 1 unit of length. C_OB++; // Add the edge (u, p) to the adjacency list of G'. G' represents the union of paths in the matching. adj_G_prime[u].push_back(p); adj_G_prime[p].push_back(u); } } /** * @brief Second DFS on the forest G'. * Finds the diameter of each connected component (which is a path). * Updates the global maximum path length found (`max_path_len`). * * @param u Current node being visited. * @param p Parent node in the DFS traversal within G'. * @param current_component_max_len Reference variable to store the diameter of the current component being processed. * @return The depth of the longest path starting from u downwards in its component path. */ int dfs2(int u, int p, int& current_component_max_len) { // Mark the current node as visited to avoid reprocessing. visited[u] = true; // Initialize maximum depths for paths starting from u downwards. int max_depth1 = 0; // Length of the longest path downwards from u. int max_depth2 = 0; // Length of the second longest path downwards from u (through a different branch, if exists). // Iterate through neighbors of u in the forest G'. for (int v : adj_G_prime[u]) { // Skip the parent node. if (v == p) continue; // Recursively call dfs2 for the child node v. The returned depth is from v downwards. // Add 1 to include the edge (u, v). int depth = dfs2(v, u, current_component_max_len) + 1; // Update the two longest path depths starting from u. if (depth > max_depth1) { max_depth2 = max_depth1; // Old max_depth1 becomes the second longest. max_depth1 = depth; // The new depth is the longest. } else if (depth > max_depth2) { max_depth2 = depth; // The new depth is the second longest. } } // The diameter of a tree component passing through node u is the sum of the two longest paths starting from u. // For a path graph, this calculation correctly finds its length (diameter). // Update the maximum diameter found within the current component. current_component_max_len = std::max(current_component_max_len, max_depth1 + max_depth2); // Return the depth of the longest path starting from u downwards. This value is used by the caller (parent node). return max_depth1; } int main() { // Use fast I/O operations. std::ios_base::sync_with_stdio(false); std::cin.tie(NULL); int N; // Number of vertices. std::cin >> N; // Resize all required vectors to N+1 to use 1-based indexing for vertices. adj_R.resize(N + 1); // adj_B is not needed after computing degrees degree_B.resize(N + 1, 0); is_odd_B.resize(N + 1, false); adj_G_prime.resize(N + 1); subtree_odd_count.resize(N + 1, 0); visited.resize(N + 1, false); // Read red edges and build the adjacency list for the Red Tree T_R. for (int i = 0; i < N - 1; ++i) { int u, v; std::cin >> u >> v; adj_R[u].push_back(v); adj_R[v].push_back(u); } // Read black edges and compute the degree of each vertex in the Black Tree T_B. for (int i = 0; i < N - 1; ++i) { int u, v; std::cin >> u >> v; degree_B[u]++; degree_B[v]++; } // Identify vertices that have an odd degree in T_B. These vertices form the set O_B. for (int i = 1; i <= N; ++i) { if (degree_B[i] % 2 != 0) { is_odd_B[i] = true; } } // Run the first DFS on T_R starting from an arbitrary root (e.g., vertex 1). // This computes C(O_B) and builds the graph G'. dfs1(1, 0); // Reset the visited flags for the second DFS pass on G'. visited.assign(N + 1, false); // Reset the maximum path length found across all components of G'. max_path_len = 0; // Iterate through all vertices from 1 to N. for(int i = 1; i <= N; ++i) { // Check if vertex i belongs to O_B and has not been visited yet by the second DFS. // Vertices in O_B are guaranteed to be endpoints (leaves) of paths in the forest G'. // Starting DFS from an unvisited O_B vertex ensures we process each component exactly once. if (is_odd_B[i] && !visited[i]) { // Variable to store the maximum length (diameter) found within this specific component of G'. int current_component_max_len = 0; // Run the second DFS starting from this O_B vertex to find the diameter of its component. dfs2(i, 0, current_component_max_len); // Update the overall maximum path length found across all components. max_path_len = std::max(max_path_len, current_component_max_len); } } // Note: Any vertex that is part of G' but not in O_B must be an internal node of some path. // Such vertices will be visited when the DFS starts from one of the path's endpoints (which are in O_B). // Therefore, iterating only through O_B vertices is sufficient to find the maximum diameter across all path components. // Calculate the final minimum total moves required. // Total moves = (Number of black edges) + (Minimum cost of red edge traversals) // Minimum cost of red edges = C(O_B) - max_path_len // Number of black edges = N - 1 long long total_moves = (long long)(N - 1) + C_OB - max_path_len; std::cout << total_moves << std::endl; return 0; }