P1119 灾后重建(基础Floyd原理的理解和运用)

洛谷:灾后重建

在这里插入图片描述

先看数据,显然很小,题目又要回答任意点到任意点的最短路,显然多源汇最短路问题义眼钉真Floyd

但询问卡死了… 5W一开始直接劝退,没什么很好的头绪。

结果此题只是一道简单的基于Floyd算法本质的签到题

蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡蔡

洛谷第一篇题解就很棒:(婴幼儿都能听懂Orz
Time_Rune大佬

祖传代码 + 注释:

#include<bits/stdc++.h>
#include<unordered_set>
#include<unordered_map>
#define mem(a,b) memset(a,b,sizeof a)
#define cinios (ios::sync_with_stdio(false),cin.tie(0),cout.tie(0))
#define sca scanf
#define pri printf
#define ul u << 1
#define ur u << 1 | 1
//#pragma GCC optimize(2)
//[博客地址](https://blog.csdn.net/weixin_51797626?t=1) 
using namespace std;

typedef long long ll;
typedef pair<int, int> PII;

const int N = 210, M = 50010, MM = 100010;
int INF = 0x3f3f3f3f, mod = 100003;
ll LNF = 0x3f3f3f3f3f3f3f3f;
int n, m, k, T, S;
int d[N][N];
int ht[N], top = 1;

inline void floyd(int k) {
    for (int i = 1; i <= n; i++)
        //虽然最外层 k 是可以任意枚举,但内层是不能变的
        //必须枚举所有有可能的边,因为 k == 1 时,有可能有 1 到 n 的边
        //为了保证时间复杂度,这是必须要更新的,不可以for(1,k),会漏信息
        for (int j = 1; j <= n; j++)
            d[i][j] = min(d[i][j], d[i][k] + d[k][j]);
            //bug —— d[i][k], d[g][k] 加号写成逗号了,min没有{}容不下那么多变量
            //直接给我淦蒙了,完全没提示bug在哪,卡了半天
            
    // 只有这坨勾吧:
    //error C2064: 项不会计算为接受 2 个参数的函数
    //message: 查看对正在编译的函数 模板 实例化“const _Ty & std::min<int, int>(const _Ty&, const _Ty&, _Pr) noexcept(<expr>)”的引用
}

int main() {
    cinios;
    
    cin >> n >> m;
    for (int i = 1; i <= n; i++) {
        cin >> ht[i];//ht是单调递增,出题人大恩大德
        for (int j = 1; j <= n; j++)
            if (i != j)d[i][j] = INF;
    }

    while (m--)
    {
        int a, b, x;
        cin >> a >> b >> x;
        a++, b++;
        d[a][b] = d[b][a] = min(d[a][b], x);
    }

    cin >> T;
    while (T--) 
    {
        int a, b, x;
        cin >> a >> b >> x; //数据保证 T 组 x 也单调递增
        a++, b++;

        //所以就不需要排序离线了
        //随着 x 更新点即可
        while (ht[top] <= x && top <= n)floyd(top++);

        //而对于当前时刻未修好的但被更新到了的村庄,进行一个简单判定即可
        if (ht[a] > x || ht[b] > x || d[a][b] == INF)cout << -1;
        else cout << d[a][b];
        cout << '\n';
    }

    return 0;
}```

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值