1 条题解
-
2
至于什么是拓扑排序,可以看看本题讨论区
思路及分析
本题为拓扑排序问题,我们需要按照特定顺序破坏摄像头,且每个摄像头只能在它不被其他摄像头监视时才能被破坏。
关键思路
建模为有向图:
每个摄像头位置作为图中的一个节点
如果摄像头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; }
信息
- ID
- 6746
- 时间
- 1000ms
- 内存
- 125MiB
- 难度
- 5
- 标签
- (无)
- 递交数
- 29
- 已通过
- 6
- 上传者