bluecode-20250409_1_补丁版本升级

245 阅读5分钟

时间限制:C/C++ 1000MS,其他语言 2000MS
内存限制:C/C++ 256MB,其他语言 512MB
难度:中等
出题人:root

描述

某测试工具升级时总选择迭代次数最多的补丁版本,已知这些补丁版本的前序版本(即依赖该版本修改发布新补丁版本),前序版本的个数<=1,且不会存在互为前序版本的情况。请给出最终可以升级的补丁版本。版本号只包含大写字母和数字。

输入描述

第一行为记录的版本迭代关系个数N,范围是[1,100000];

第二行到第N+1行:每行包含两个字符串,第一个字符串为当前版本,第二个字符串为前序版本,用空格隔开。字符串包含字符个数为[1,100],没有前序版本的第二个字符串固定为NA。

输出描述

所有迭代次数最多的补丁版本号字符串列表,多个版本号以字典序排序排列,用空格隔开。

用例输入 1 **

6  
CN001 BF0001  
BF001 AZ2001  
AZ0001 NA
BF0010 AZ0001
AWOO01 NA
BF0011 AZ0001

用例输出 1 **

CN0010

用例输入 2 **

3
BF0001 AZ0001
AZ0001 NA
BF00011 AZ0001

用例输出 2 **

BF0001 BF00011

提示

样例1解释
AZ0001和AWV0001没有前序版本,各选代了0次;
BF0001,BF0010和BF0011的前序版本为AZ0001,各选代了1次;
CN0010的前序版本为BF0001,BF0001的前序版本为AZ0001,选代了2次。
根据要求选择迭代次数最多的补丁版本,因此输出CN0010。

样例2解释
AZ0001没有前序版本,选代了0次;
BF0001和BF00011的前序版本为AZ0001,各选代了1次;
根据要求选择迭代次数最多的补丁版本,有多个版本号时以字典序排列,因此输出BF0001 BF00011.

#include <iostream> // For input/output operations (cin, cout)
#include <vector>   // For std::vector
#include <string>   // For std::string
#include <map>      // For std::map (associative container)
#include <set>      // For std::set (ordered unique elements)
#include <queue>    // For std::queue (FIFO data structure for BFS)
#include <algorithm> // For std::sort and std::max

int main() {
    // Optimize C++ standard streams for faster Input/Output.
    // This is often helpful in competitive programming to avoid Time Limit Exceeded.
    std::ios_base::sync_with_stdio(false);
    std::cin.tie(NULL);

    int n; // Number of version iteration relationship records
    // Read the number of records. Handle potential read error or invalid N.
    if (!(std::cin >> n) || n < 1) {
        // The problem constraints state N >= 1, but robust code handles edge cases.
        // If N=0 or read fails, output an empty line as there are no versions.
        std::cout << std::endl;
        return 0;
    }

    // Map to store the direct predecessor for each version: current_version -> previous_version
    std::map<std::string, std::string> prev_map;
    // Map to store the reversed dependency graph (adjacency list): previous_version -> list<current_version>
    // This is useful for traversing from roots downwards (in terms of iteration) using BFS.
    std::map<std::string, std::vector<std::string>> adj_map;
    // Set to store all unique version strings encountered in the input.
    // Using a set automatically handles duplicates.
    std::set<std::string> all_versions;

    // Read all N dependency records
    for (int i = 0; i < n; ++i) {
        std::string current_version, previous_version;
        // Read the current version and its previous version. Handle read errors.
        if (!(std::cin >> current_version >> previous_version)) {
             return 1; // Indicate an error occurred during input reading
        }

        // Add the current version to the set of all versions.
        all_versions.insert(current_version);
        // Store the predecessor relationship in the map.
        prev_map[current_version] = previous_version;

        // If the previous version is not "NA" (meaning it's a valid version string)
        if (previous_version != "NA") {
            // Add the previous version to the set of all versions.
            all_versions.insert(previous_version);
            // Add an edge from the previous version to the current version in the reversed graph.
            // `adj_map[key]` automatically creates an empty vector if the key doesn't exist.
            adj_map[previous_version].push_back(current_version);
        }
    }

    // Identify the root versions. A version is a root if:
    // 1. It does not appear as a `current_version` in the input (only as `previous_version`).
    //    In this case, it won't be a key in `prev_map`.
    // 2. Its `previous_version` is explicitly "NA".
    std::set<std::string> roots;
    for (const std::string& v : all_versions) {
        // Find the version 'v' in the predecessor map.
        auto it = prev_map.find(v);
        // Check if 'v' is not found in the map OR if its value is "NA".
        if (it == prev_map.end() || it->second == "NA") {
            roots.insert(v); // Add it to the set of roots.
        }
    }

    // Map to store the calculated iteration count (depth from a root) for each version.
    std::map<std::string, int> iter_count_map;
    // Queue for performing Breadth-First Search (BFS) starting from the roots.
    std::queue<std::string> q;
    // Variable to keep track of the maximum iteration count found. Initialize to 0.
    // The minimum iteration count is 0 (for root versions).
    int max_iter_count = 0;

    // Initialize the BFS:
    // Add all identified root versions to the queue and set their iteration count to 0.
    for (const std::string& r : roots) {
        // Check if the root has already been added (safety check, unlikely needed with set)
        if (iter_count_map.find(r) == iter_count_map.end()) {
             iter_count_map[r] = 0; // Set iteration count for root to 0
             q.push(r);             // Add root to the BFS queue
        }
        // Note: `max_iter_count` remains 0 if only roots exist.
    }

    // Perform BFS to calculate iteration counts for all versions reachable from roots.
    while (!q.empty()) {
        // Get the version at the front of the queue.
        std::string u = q.front();
        q.pop(); // Remove it from the queue

        // Get the iteration count of the current version 'u'.
        // We know 'u' exists in iter_count_map because it was added before being pushed to queue.
        int current_count = iter_count_map[u];

        // Find the neighbors of 'u' in the reversed graph (i.e., versions that depend on 'u').
        auto adj_it = adj_map.find(u);
        // Check if 'u' actually has any dependent versions.
        if (adj_it != adj_map.end()) {
            // Iterate through all versions 'v' that have 'u' as their predecessor.
            for (const std::string& v : adj_it->second) {
                // If version 'v' has not been visited yet (its count hasn't been calculated).
                // This condition is sufficient because the graph is a forest (no cycles, <=1 predecessor),
                // ensuring we find the correct depth via the unique path from the root.
                if (iter_count_map.find(v) == iter_count_map.end()) {
                    // Calculate the iteration count for 'v'.
                    int next_count = current_count + 1;
                    iter_count_map[v] = next_count; // Store the count.
                    // Update the overall maximum iteration count found so far.
                    max_iter_count = std::max(max_iter_count, next_count);
                    // Add 'v' to the queue to process its dependents later.
                    q.push(v);
                }
            }
        }
    }

    // Collect all versions that have the maximum iteration count.
    std::vector<std::string> result_versions;
    // Iterate through all the versions for which an iteration count was calculated.
    // Since the graph is a forest and BFS starts from all roots, this map should contain
    // all versions involved in the dependency chains.
    for (const auto& pair : iter_count_map) {
        // If the version's iteration count matches the maximum count found.
        if (pair.second == max_iter_count) {
            // Add the version string (the key of the pair) to the result list.
            result_versions.push_back(pair.first);
        }
    }

    // Sort the resulting versions lexicographically (alphabetical/numerical order).
    std::sort(result_versions.begin(), result_versions.end());

    // Print the sorted versions, separated by spaces.
    for (size_t i = 0; i < result_versions.size(); ++i) {
        std::cout << result_versions[i] << (i == result_versions.size() - 1 ? "" : " ");
        // Add a space after each version except the last one.
    }
    std::cout << std::endl; // Print a newline character at the end of the output.

    return 0; // Indicate successful program execution.
}