【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 分享这个秘密,反之亦然。

秘密共享是瞬时发生的。也就是说在同一时间,一个专家不光可以接收到秘密,还能在其他会议上与其他专家分享。

在所有会议都结束之后,按顺序输出所有知晓这个秘密的专家列表。为了保护专家隐私,输出专家编号减一后的结果。
 

输入

第一行整数n,m和firstPerson.
接下来m行,每行3个整数表示会议信息.
2n,m105,1xi,yin,xi!=yi2≤n,m≤105,1≤xi,yi≤n,xi!=yi
1timei105,1firstPersonn1≤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即可。场景二:第一轮遍历中,先遍历到某场会议,此时两位专家都不知道秘密,在后面的遍历中,这两位专家均没有被分享秘密,这时需要将两位专家从合并的集合中分离出来,如果不分离出来,在后面某时刻,如果这两位专家其中一个知道了秘密,那么会认为这两位专家都知道了秘密,但事实上,由于该时刻已过去,秘密无法分享给另一位专家。

当然也可以采用dij做法,跟最短路径问题大亭相近,具体可以见【C++】ZZ2193-城市之路 解题精讲 - 冯子坤 - 博客园 (cnblogs.com)

代码

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
****************************************************************/

 

posted @ 2022-06-11 22:11  冯子坤  阅读(53)  评论(0编辑  收藏  举报