算法:告警抑制

题目:


告警抑制,是指高优先级抑制低优先级告警的规则 。高优先级告警产生后,低优先级告警不再产生。请根据原始告警列表和告警抑制关系,给出实际产生的告警列表。
注意:不会出现循环抑制的情况。
告警不会传递,比如 A>B,B>C 这种情况下A不会直接抑制C。  但被抑制的告警仍然可以抑制其他低优先级的告警。

输入描述:

第一行位数字N,表示告警抑制关系个数,0<=N<=120
接下来N行,每行是由空格分隔的两个告警ID,例如:id1 id2,表示id1抑制id2,告警ID的格式为大写字母+0个或者1个数字。 最后一行为告警产生列表,列表长度[1,100].


输出描述:
真实产生的告警列表

输入举例:
2
A B
B C
A B C D E


输出为:
A D E
说明A抑制了B,B抑制了C,最后实际告警为 A D E

解题思路:

  • 首先,需要将告警抑制关系用一个图来表示。图中的点表示告警,如果告警A可以抑制告警B,那么在A和B之间连一条有向边。因为告警不会传递,所以这是一个有向无环图(DAG)。
  • 其次,需要将原始告警列表中被抑制的告警全部删除。具体做法是从仅有入度的节点(即没有被任何其他节点抑制的节点)开始,沿着有向边一直走到叶子节点,把路径上所有的节点都标记为被删除。这个过程可以用拓扑排序来实现。
  • 最后,输出没有被删除的节点即可。

Java:

import java.util.*;

public class Main {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt(); // 告警抑制关系个数
        sc.nextLine();
        Map> graph = new HashMap<>(); // 告警抑制关系图
        Set nodes = new HashSet<>(); // 所有告警节点
        for (int i = 0; i < n; i++) {
            String[] parts = sc.nextLine().split(" ");
            String from = parts[0], to = parts[1];
            // 添加节点
            nodes.add(from);
            nodes.add(to);
            // 添加有向边
            graph.computeIfAbsent(from, k -> new HashSet<>()).add(to);
        }
        String[] alerts = sc.nextLine().split(" "); // 原始告警列表
        Set toDelete = new HashSet<>(); // 待删除的节点
        // 拓扑排序
        Queue queue = new LinkedList<>();
        // 找到所有入度为0的节点
        Set indegrees = new HashSet<>(nodes);
        for (Set edges : graph.values()) {
            indegrees.removeAll(edges);
        }
        queue.addAll(indegrees);
        while (!queue.isEmpty()) {
            String node = queue.poll();
            for (String neighbor : graph.getOrDefault(node, Collections.emptySet())) {
                // 如果这个节点还没有被删除,才将其度数减1
                if (!toDelete.contains(neighbor)) {
                    toDelete.add(neighbor);
                    queue.offer(neighbor);
                }
            }
        }
        // 输出剩下的节点
        for (String alert : alerts) {
            if (!toDelete.contains(alert)) {
                System.out.print(alert + " ");
            }
        }
    }
}

你可能感兴趣的:(java)