1 条题解

  • 2
    @ 2025-7-2 1:47:20

    至于什么是拓扑排序,可以看看本题讨论区

    思路及分析

    本题为拓扑排序问题,我们需要按照特定顺序破坏摄像头,且每个摄像头只能在它不被其他摄像头监视时才能被破坏。

    关键思路

    建模为有向图:

    每个摄像头位置作为图中的一个节点

    如果摄像头A能监视位置B,则建立一条A→B的有向边

    这表示必须先破坏A,才能破坏B(因为A被破坏后B就不再被监视)

    拓扑排序:

    入度为0的节点表示当前不被任何摄像头监视的位置

    可以安全破坏这些位置上的摄像头

    破坏后,更新其他摄像头的入度

    算法流程:

    统计每个位置的入度(被多少摄像头监视)

    使用队列处理入度为0的位置

    每破坏一个摄像头,减少它监视的位置的入度

    如果产生新的入度为0的位置,加入队列

    AC code

    #include <bits/stdc++.h>
    using namespace std;
    const int ml = 500 + 50;
    vector<int> G[ml];  // 邻接表,记录每个摄像头监视的位置
    int a[ml], ru[ml];  // a记录位置是否有摄像头,ru记录入度
    int n;
    
    int main() {
        cin >> n;
        for(int i=1; i<=n; i++) {
            int x, m, y;
            cin >> x >> m;
            a[x]++;  // 标记x位置有摄像头
            while(m--) {
                cin >> y;
                G[x].push_back(y);  // x能监视y
                ru[y]++;  // y的入度+1
            }
        }
        
        queue<int> que;
        // 找出所有初始入度为0的位置(可以直接破坏)
        for(int i=1; i<=500; i++) {
            if(ru[i] == 0 && a[i]) {  // 有摄像头且不被监视
                que.push(i);
            }
        }
        
        int ans = 0;  // 记录已破坏的摄像头数量
        while(!que.empty()) {
            int now = que.front();
            que.pop();
            ans += a[now];  // 破坏这个位置的摄像头
            
            // 更新被这个摄像头监视的位置
            for(auto it : G[now]) {
                ru[it]--;  // 这些位置少一个监视者
                if(ru[it] == 0 && a[it]) {  // 如果不再被监视且有摄像头
                    que.push(it);
                }
            }
        }
        
        if(n == ans) cout << "YES" << endl;
        else cout << n - ans << endl;
        
        return 0;
    }
    
    • 1

    信息

    ID
    6746
    时间
    1000ms
    内存
    125MiB
    难度
    5
    标签
    (无)
    递交数
    29
    已通过
    6
    上传者