时间限制: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.
}