java解法

第一行输入依赖关系(格式如A-B,B-C),解析为依赖对列表rels。
第二行输入故障服务(格式如A,C),解析为故障服务列表fails。
构建依赖关系映射:

使用depMap记录服务之间的依赖关系,键是被依赖的服务,值是依赖该服务的服务集合。
使用orderMap记录服务的输入顺序,用于最终按顺序输出。
故障传播:

对于每个故障服务,使用栈遍历其依赖的所有服务,将受影响的服务标记为故障。
筛选未受影响的服务:

遍历所有服务,排除被标记为故障的服务,得到仍然可用的服务列表。
按输入顺序输出:

对剩下的可用服务列表,按照orderMap中记录的顺序排序并输出。

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);

        // 读取第一行输入:依赖关系字符串,格式如"A-B,B-C"
        String relInput = sc.nextLine();
        List<String> relPairs = split(relInput, ',');

        // 将依赖关系解析为Pair对象的列表
        List<Pair<String, String>> rels = new ArrayList<>();
        for (String pStr : relPairs) {
            List<String> p = split(pStr, '-');
            rels.add(new Pair<>(p.get(0), p.get(1))); // p.get(0)为依赖服务,p.get(1)为被依赖服务
        }

        // 读取第二行输入:故障服务字符串,格式如"A,C"
        String failInput = sc.nextLine();
        List<String> fails = split(failInput, ',');

        // 输出结果
        System.out.println(getActive(rels, fails));
    }

    // 工具方法:将字符串按指定分隔符拆分为列表
    public static List<String> split(String s, char d) {
        return Arrays.asList(s.split(String.valueOf(d))); // 使用String的split方法分隔字符串
    }

    // 核心方法:根据依赖关系和故障服务,计算仍然可用的服务
    public static String getActive(List<Pair<String, String>> rels, List<String> fails) {
        // 依赖图:键为被依赖的服务,值为依赖该服务的服务集合
        Map<String, Set<String>> depMap = new HashMap<>();
        // 故障服务集合,用于快速判断服务是否故障
        Set<String> failSet = new HashSet<>(fails);
        // 服务的顺序映射,用于输出时排序
        Map<String, Integer> orderMap = new HashMap<>();

        // 构建依赖图和顺序映射
        int idx = 0;
        for (Pair<String, String> rel : rels) {
            String dep = rel.getKey();   // 依赖的服务
            String prov = rel.getValue(); // 被依赖的服务

            // 构建依赖图:被依赖服务prov对应依赖它的服务集合
            depMap.computeIfAbsent(prov, k -> new HashSet<>()).add(dep);

            // 记录服务的顺序(如果服务未出现过则记录)
            orderMap.putIfAbsent(dep, idx++);
            orderMap.putIfAbsent(prov, idx++);
        }

        // 模拟故障传播:从每个故障服务开始,标记所有受影响的服务
        for (String fail : fails) {
            Stack<String> stk = new Stack<>(); // 使用栈进行深度优先搜索
            stk.push(fail);

            while (!stk.isEmpty()) {
                String svc = stk.pop(); // 弹出当前服务

                // 如果当前服务有依赖服务,处理这些服务
                if (depMap.containsKey(svc)) {
                    for (String dep : depMap.get(svc)) {
                        // 如果依赖的服务未被标记为故障,则标记为故障并加入栈
                        if (!failSet.contains(dep)) {
                            failSet.add(dep);
                            stk.push(dep);
                        }
                    }
                    depMap.remove(svc); // 处理完当前服务后,从依赖图中移除
                }
            }
        }

        // 收集仍然可用的服务(不在故障集合中的服务)
        List<String> operList = new ArrayList<>();
        for (Map.Entry<String, Integer> entry : orderMap.entrySet()) {
            if (!failSet.contains(entry.getKey())) {
                operList.add(entry.getKey());
            }
        }

        // 如果所有服务都不可用,返回逗号
        if (operList.isEmpty()) {
            return ",";
        }

        // 按服务的输入顺序排序
        operList.sort(Comparator.comparingInt(orderMap::get));

        // 将可用服务列表拼接为逗号分隔的字符串并返回
        return String.join(",", operList);
    }

    // 辅助类:表示依赖关系的键值对
    public static class Pair<K, V> {
        private final K key;   // 键:依赖服务
        private final V value; // 值:被依赖服务

        public Pair(K key, V value) {
            this.key = key;
            this.value = value;
        }

        public K getKey() {
            return key;
        }

        public V getValue() {
            return value;
        }
    }
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C++解法

第一行输入描述服务之间的依赖关系(如 A-B,B-C),将其解析为relations列表,存储为键值对(dependent 和 provider)。
第二行输入故障服务列表(如 A,C),将其存储为字符串列表failures。
构建依赖图和服务顺序:

使用 dependencyMap 记录服务之间的依赖关系:
键是被依赖的服务,值是依赖该服务的服务集合。
使用 appearanceOrder 记录每个服务首次出现的顺序,用于最终结果排序。
模拟故障传播:

对于每个故障服务,使用栈(DFS)遍历其依赖的所有服务,标记为故障,并将它们加入栈中,直到没有更多服务受影响。
筛选可用服务:

遍历所有服务,排除已标记为故障的服务,剩余的服务即为仍然可用的服务。
按输入顺序输出:

对可用服务按照 appearanceOrder 的顺序排序,并用逗号拼接输出。如果没有可用服务,直接输出 ,。

#include 
#include 
#include 
#include 
#include 
#include 
#include 

using namespace std;

// 工具函数:将字符串按指定分隔符分割为子字符串列表
vector<string> split(const string& s, char delimiter) {
    vector<string> tokens;
    string token;
    istringstream tokenStream(s);
    while (getline(tokenStream, token, delimiter)) {
        tokens.push_back(token);
    }
    return tokens;
}

// 核心函数:根据依赖关系和故障服务,计算仍然可用的服务
string determineActiveServices(const vector<pair<string, string>>& relations, const vector<string>& failures) {
    // 依赖图:被依赖服务 -> 依赖它的服务集合
    map<string, set<string>> dependencyMap;
    // 故障服务集合,用于快速判断服务是否故障
    set<string> failureSet(failures.begin(), failures.end());
    // 服务顺序映射:记录服务首次出现的顺序,用于最终排序
    map<string, int> appearanceOrder;
    
    int index = 0;
    // 构建依赖图和服务顺序映射
    for (const auto& relation : relations) {
        const string& dependent = relation.first;   // 依赖服务
        const string& provider = relation.second;  // 被依赖服务
        
        // 构建依赖图:被依赖服务指向依赖它的服务
        dependencyMap[provider].insert(dependent);

        // 记录服务的输入顺序
        if (appearanceOrder.find(dependent) == appearanceOrder.end()) {
            appearanceOrder[dependent] = index++;
        }
        if (appearanceOrder.find(provider) == appearanceOrder.end()) {
            appearanceOrder[provider] = index++;
        }
    }

    // 模拟故障传播
    for (const auto& failure : failures) {
        stack<string> stack; // 使用栈进行深度优先搜索(DFS)
        stack.push(failure);

        while (!stack.empty()) {
            string service = stack.top(); // 弹出栈顶服务
            stack.pop();

            // 如果当前服务有依赖服务,处理这些依赖服务
            if (dependencyMap.find(service) != dependencyMap.end()) {
                for (const auto& dependent : dependencyMap[service]) {
                    // 如果依赖服务尚未被标记为故障,则标记为故障并加入栈
                    if (failureSet.find(dependent) == failureSet.end()) {
                        failureSet.insert(dependent);
                        stack.push(dependent);
                    }
                }
                // 从依赖图中移除当前服务
                dependencyMap.erase(service);
            }
        }
    }

    // 筛选仍然可用的服务(不在故障集合中的服务)
    vector<string> operationalList;
    for (const auto& entry : appearanceOrder) {
        if (failureSet.find(entry.first) == failureSet.end()) {
            operationalList.push_back(entry.first);
        }
    }

    // 如果所有服务都不可用,返回逗号
    if (operationalList.empty()) {
        return ",";
    }

    // 按服务的输入顺序排序
    sort(operationalList.begin(), operationalList.end(), [&](const string& a, const string& b) {
        return appearanceOrder[a] < appearanceOrder[b];
    });

    // 将可用服务列表拼接为逗号分隔的字符串
    string result = operationalList[0];
    for (size_t i = 1; i < operationalList.size(); ++i) {
        result += "," + operationalList[i];
    }

    return result;
}

int main() {
    // 读取第一行输入:依赖关系字符串
    string relationsInput;
    getline(cin, relationsInput);
    vector<string> relationsPairs = split(relationsInput, ',');

    // 将依赖关系字符串解析为键值对列表
    vector<pair<string, string>> relations;
    for (const auto& pairStr : relationsPairs) {
        vector<string> pair = split(pairStr, '-');
        relations.emplace_back(pair[0], pair[1]);
    }

    // 读取第二行输入:故障服务字符串
    string failuresInput;
    getline(cin, failuresInput);
    vector<string> failures = split(failuresInput, ',');

    // 输出结果
    cout << determineActiveServices(relations, failures) << endl;

    return 0;
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

C解法

更新中
 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

JS解法

第一行输入表示依赖关系,格式如 A-B,B-C,解析为二维数组 rel,其中每个元素是 [依赖服务, 被依赖服务]。
第二行输入表示故障服务,格式如 A,C,解析为数组 brk。
构建依赖关系图和服务顺序:

使用 nxt 构建依赖关系图:
键是被依赖的服务,值是依赖它的服务集合。
使用 fst 记录每个服务的输入顺序,用于最终结果的排序。
故障传播:

遍历故障服务列表 brk,从每个故障服务开始,递归删除所有依赖它的服务,并从依赖关系图中移除。
筛选可用服务:

剩余在依赖关系图 nxt 中的服务即为未受影响的服务。
按 fst 中的顺序对这些服务进行排序。
返回结果:

如果没有可用服务,返回 ,。
否则,返回按顺序排序后,用逗号拼接的可用服务列表。

const readline = require("readline");

// 创建标准输入输出接口
const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout,
});

// 存储输入的两行数据
const ln = [];
rl.on("line", (line) => {
    ln.push(line);

    // 当两行输入均已读取时处理
    if (ln.length === 2) {
        // 第一行解析为依赖关系数组
        const rel = ln[0].split(",").map((p) => p.split("-"));
        // 第二行解析为故障服务数组
        const brk = ln[1].split(",");

        // 计算未受影响的服务并输出
        console.log(getNorm(rel, brk));

        // 清空输入数组,准备下一组输入
        ln.length = 0;
    }
});

// 核心函数:根据依赖关系和故障服务,计算未受影响的服务
function getNorm(rel, brk) {
    // 依赖关系图:记录被依赖服务 -> 依赖它的服务集合
    const nxt = {};
    // 服务顺序:记录每个服务首次出现的顺序
    const fst = {};
    let idx = 0;

    // 构建依赖关系图和服务顺序
    for (let [c, f] of rel) {
        // 初始化依赖关系图条目
        if (!nxt[c]) nxt[c] = new Set();
        if (!nxt[f]) nxt[f] = new Set();
        // 被依赖服务 f 增加依赖它的服务 c
        nxt[f].add(c);

        // 记录服务的顺序
        if (!fst[c]) fst[c] = idx++;
        if (!fst[f]) fst[f] = idx++;
    }

    // 模拟故障传播:从每个故障服务开始,递归删除所有依赖它的服务
    for (let s of brk) {
        del(nxt, s);
    }

    // 收集剩余未受影响的服务
    const res = Object.keys(nxt);
    // 如果所有服务都受影响,返回 ","
    if (res.length == 0) return ",";
    // 按服务的输入顺序排序并返回结果
    return res.sort((a, b) => fst[a] - fst[b]).join(",");
}

// 辅助函数:递归删除所有受影响的服务
function del(nxt, s) {
    // 如果服务 s 存在于依赖关系图中
    if (nxt[s]) {
        // 获取所有依赖于服务 s 的服务集合
        const rm = nxt[s];
        // 从依赖关系图中移除服务 s
        delete nxt[s];

        // 对每个依赖于服务 s 的服务,递归删除
        for (let ss of rm) {
            del(nxt, ss);
        }
    }
}

 class="hljs-button signin active" data-title="登录复制" data-report-click="{"spm":"1001.2101.3001.4334"}">

注意:

如果发现代码有用例覆盖不到的情况,欢迎反馈!会在第一时间修正,更新。
解题不易,如对您有帮助,欢迎点赞/收藏

注:本文转载自blog.csdn.net的CodeClimb的文章"https://blog.csdn.net/CodeClimb/article/details/145052246"。版权归原作者所有,此博客不拥有其著作权,亦不承担相应法律责任。如有侵权,请联系我们删除。
复制链接

评论记录:

未查询到任何数据!