刷好题,固基础-11

前置知识点:Kruskal算法

详细讲解:Kruskal算法简易教程(附最全注释代码实现)_kruskal算法测试实例-CSDN博客

环游小岛

这是一个关于小岛环游的考验。在这个考验中,有n座小岛分布在海洋中,小岛与小岛之间的距离有近有远。为了到达不同的小岛,你可以选择游泳或者搭乘快艇。
现给出m对小岛之间的距离,距离用 w 来表示你可以通过消耗 w 的体力值从其中一个小岛到达另一个小岛。这个体力值可以是正值,代表需要消耗体力游泳到达;也可以是负值,代表可以搭乘快艇轻松到达。换句话说,正值表示需要付出额外的努力,而负值则表示可以省下体力。
在这个环游计划中,你可以选择在任意一座小岛上休息,休息的时间没有限制。这样可以恢复体力,并为接下来的旅程做好准备。
现在给出了 q 个询问,每个询问包含三个信息:起点、终点和你当前的体力值上限。问题是,能否凭借当前的体力值上限完成从起点到终点的环游计划。

输入格式:

第一行包含两个整数n、m、q ,
接下来 m 行,每行包含三个整数x、y、w,w 代表 x 和 y 两个小岛间的距离,
接下来 q 行,每行包含三个整数x、y、t,问是否能够凭借体力值上限 t 完成从 x 到 y 的环游计划。

1<=n<=1e5,1<=m<=1e5,1<=q<=1e5
1<=x,y<=n,0<=∣w∣<=1e9,0<=t<=1e9

输出格式:

共 q 行,每行根据询问给出答案,若可以完成该询问的环游计划则输出 YES ,反之则输出 NO 。

输入样例:

3 3 3
1 2 1
2 3 2
1 3 3
1 3 2
1 2 0
2 3 1

输出样例:

YES
NO
NO

 思路:Kruskal算法+并查集--通过对每条边的升序排列,从这条边可以走出的最小生成图,通过并查集来判断查询的起,终点是否在一个集合内

//Kruskal
//概论:通过对每条边的升序排列,从这条边可以走出的最小生成图来判断查询是否可靠
//内涵迭代思想
#include<bits/stdc++.h>
using namespace std;
const int N = 1e6+7, inf = 0x3f3f3f3f, mod = 1e9+7, eps = 1e-9;

int fa[N], ans[N];
vector<array<int, 3>> edge;

int find(int x){
    if(fa[x] != x)    fa[x] = find(fa[x]);
    return fa[x];
}

int main(){
    int n, m, q;    cin >> n >> m >> q;
    for(int i = 1; i <= n; ++i)    fa[i] = i;    //初始化
    for(int i = 0; i < m; ++i){
        int x, y, w;    cin >> x >> y >> w;
        edge.push_back({w, x, y});
    }
    sort(edge.begin(), edge.end());    //体力升序排序
    vector<array<int,4>> ask;
    for(int i = 0; i < q; ++i){
        int x, y, t;    cin >> x >> y >> t;
        ask.push_back({t, x, y, i});
    }
    sort(ask.begin(), ask.end());

    int now = 0;
    for(auto [w, x, y] : edge){    //对每一条边
        while(now < ask.size() && w > ask[now][0]){    //当前体力大于需要的体力
            auto [t, st, ed, idx] = ask[now];
            if(find(st) == find(ed))    ans[idx] = 1;    //如果节点已连接,YES
            now++;
        }
        fa[find(x)] = find(y);
    }

    for(int i = now; i < ask.size(); ++i){
        auto [t, st, ed, idx] = ask[i];
        if(find(st) == find(ed))    ans[idx] = 1;
    }

    for(int i = 0; i < q; ++i)
        if(ans[i])    cout << "YES\n";
        else    cout << "NO\n";
    return 0;
}

  • 4
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值