【C++】ZZ1854-找出知晓秘密的所有专家 解题精讲
【Horn Coding Studio】CPP编程专栏
题目
题目描述
给你一个整数 nn ,表示有 nn 个专家从 11 到 nn 编号。
再给你mm个线上会议的信息[xi,yi,timei][xi,yi,timei] 表示专家 xixi 和专家 yiyi 在时间 timeitimei 要开一场会。一个专家可以同时参加多场会议。
最后,给你一个整数 firstPersonfirstPerson。
专家 1 有一个秘密 ,最初,他在时间 0 将这个秘密分享给了专家 firstPerson 。
接着,这个秘密会在每次有知晓这个秘密的专家参加会议时进行传播。更正式的表达是,每次会议,如果专家 xi 在时间 timei 时知晓这个秘密,那么他将会与专家 yi 分享这个秘密,反之亦然。
秘密共享是瞬时发生的。也就是说在同一时间,一个专家不光可以接收到秘密,还能在其他会议上与其他专家分享。
在所有会议都结束之后,按顺序输出所有知晓这个秘密的专家列表。为了保护专家隐私,输出专家编号减一后的结果。
再给你mm个线上会议的信息[xi,yi,timei][xi,yi,timei] 表示专家 xixi 和专家 yiyi 在时间 timeitimei 要开一场会。一个专家可以同时参加多场会议。
最后,给你一个整数 firstPersonfirstPerson。
专家 1 有一个秘密 ,最初,他在时间 0 将这个秘密分享给了专家 firstPerson 。
接着,这个秘密会在每次有知晓这个秘密的专家参加会议时进行传播。更正式的表达是,每次会议,如果专家 xi 在时间 timei 时知晓这个秘密,那么他将会与专家 yi 分享这个秘密,反之亦然。
秘密共享是瞬时发生的。也就是说在同一时间,一个专家不光可以接收到秘密,还能在其他会议上与其他专家分享。
在所有会议都结束之后,按顺序输出所有知晓这个秘密的专家列表。为了保护专家隐私,输出专家编号减一后的结果。
输入
第一行整数n,m和firstPerson.
接下来m行,每行3个整数表示会议信息.
2≤n,m≤105,1≤xi,yi≤n,xi!=yi2≤n,m≤105,1≤xi,yi≤n,xi!=yi
1≤timei≤105,1≤firstPerson≤n1≤timei≤105,1≤firstPerson≤n
接下来m行,每行3个整数表示会议信息.
2≤n,m≤105,1≤xi,yi≤n,xi!=yi2≤n,m≤105,1≤xi,yi≤n,xi!=yi
1≤timei≤105,1≤firstPerson≤n1≤timei≤105,1≤firstPerson≤n
输出
输出一行专家编号列表表示答案.
样例输入 复制
6 3 1
1 2 5
2 3 8
1 5 10
样例输出 复制
0 1 2 4
提示
本来是1 2 3 5号专家知道秘密,为保护隐私输出编号减一后的结果,也就是0 1 2 4.
来源
知识点普及
见【C++】ZZ1279-畅通工程 解题精讲 - 冯子坤 - 博客园 (cnblogs.com)
一点即通
每次分享秘密,可以看作把两个专家合并到一个集合中,因此采用并查集求解。
最开始,每个专家的祖先节点记为自己,由于秘密传播是通过会议进行的,时间靠后的会议不可能传播到时间靠前的会议,因此需要先对meetings数组按照会议时间排序。
排序完成后,遍历所有时刻。同一时刻可能存在多场会议,由于秘密共享是瞬时发生的,且同一时刻的会议是乱序的,不存在先后,所以对每一时刻的处理分为两步:
-
第一轮遍历:首先判断两位专家中是否有人知道秘密,若有人知道秘密,则将两位专家的祖先节点都置为0。另外,无论两位专家是否有人知道秘密,都要将两个专家合并,因为同一时刻的其他会议中,可能有其他知道秘密的专家将秘密分享给这两位中的任何一个。
-
第二轮遍历:处理两种情况,场景一:第一轮遍历中,先遍历到某场会议,此时两位专家都不知道秘密,但在后面的遍历中,其中一位专家知道了秘密,由于上一步做了合并集合处理,此时将两位专家的祖先节点均置为0即可。场景二:第一轮遍历中,先遍历到某场会议,此时两位专家都不知道秘密,在后面的遍历中,这两位专家均没有被分享秘密,这时需要将两位专家从合并的集合中分离出来,如果不分离出来,在后面某时刻,如果这两位专家其中一个知道了秘密,那么会认为这两位专家都知道了秘密,但事实上,由于该时刻已过去,秘密无法分享给另一位专家。
代码
ZZOJ AC
LuoguOJ *没有这道题目
#include <bits/stdc++.h> using namespace std; int n, m, st, k, dis[1000050],vis[1000050],head[1000050]; struct Edge { int to, next, w; } edge[1000050]; void add(int u, int v, int w) { edge[k].to = v; edge[k].w = w; edge[k].next = head[u]; head[u] = k++; } struct qnode { int u, t; bool operator < (const qnode &r) const { return t > r.t; } }; priority_queue<qnode> que; void dij() { que.push({1, 0}); que.push({st, 0}); for(int i = 1; i <= n; i++) dis[i] = 1e9; dis[1] = dis[st] = 0; while(que.size()) { qnode tmp = que.top(); que.pop(); int u = tmp.u; int t = tmp.t; if(vis[u] == 1) continue; vis[u] = 1; for(int i = head[u]; i != -1; i = edge[i].next) { int w = edge[i].w; int to = edge[i].to; if(w < t) continue; if(dis[to] > w) { dis[to] = w; que.push({to, dis[to]}); } } } } int main() { cin>>n>>m>>st; for(int i = 1; i <= n; i++) { head[i] = -1; } for(int i = 1; i <= m; i++) { int u, v, w; cin>>u>>v>>w; add(u, v, w); add(v, u, w); } dij(); for(int i = 1; i <= n; i++) { if(dis[i] != 1e9) { cout<<i-1<<" "; } } return 0; } /************************************************************** User: FZK Language: C++ Result: 正确 Time:106 ms Memory:26088 kb ****************************************************************/