AcWing 1128. 信使

AcWing 1128. 信使

题目传送门

一、题目描述

战争时期,前线有 n 个哨所,每个哨所可能会与其他若干个哨所之间有通信联系。

信使负责在哨所之间传递信息,当然,这是要花费一定时间的(以天为单位)。

指挥部设在 第一个 哨所。

当指挥部下达一个命令后,指挥部就派出若干个信使向与指挥部相连的哨所送信。

当一个哨所接到信后,这个哨所内的信使们也以同样的方式向其他哨所送信。信在一个哨所内停留的时间可以忽略不计。

直至所有 n 个哨所全部接到命令后,送信才算成功。

因为准备充足,每个哨所内都安排了足够的信使(如果一个哨所与其他 k 个哨所有通信联系的话,这个哨所内至少会配备 k 个信使)。

现在总指挥请你编一个程序,计算出完成整个送信过程 最短需要多少时间

输入格式
1 行有两个整数 nm,中间用 1 个空格隔开,分别表示有 n 个哨所和 m 条通信线路。

2m+1 行:每行三个整数 ijk,中间用 1 个空格隔开,表示第 i 个和第 j 个哨所之间存在 双向 通信线路,且这条线路要花费 k 天。

输出格式
一个整数,表示完成整个送信过程的最短时间。

如果不是所有的哨所都能收到信,就输出1

二、题目解析

  • 单源最短路径,一般采用堆优化版本的Dijkstra算法
  • 最短距离的最大值,也就是 完成整个送信过程的最短时间

三、Dijkstra+PII

#include <bits/stdc++.h>
using namespace std;
typedef pair<int, int> PII;

const int N = 110;
const int M = 2 * 210; //无向边,开两倍

int n, m;
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int d[N];
bool st[N];

int dijkstra() {
    int res = 0, cnt = 0;

    //初始化为正无穷
    memset(d, 0x3f, sizeof d);
    d[1] = 0; // 1号点为出发点,距离为0
    //小顶堆
    priority_queue<PII, vector<PII>, greater<>> q;
    q.push({0, 1});

    while (q.size()) {
        auto u = q.top();
        q.pop();

        if (st[u.second]) continue; // Dijkstra第一次出队列为最小值
        st[u.second] = true;

        //求所有最短距离的最大值
        res = max(res, u.first);
        //记录到达的节点个数
        cnt++;

        for (int i = h[u.second]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] > d[u.second] + w[i]) {
                d[j] = d[u.second] + w[i];
                q.push({d[j], j});
            }
        }
    }
    //如果可以成功到达每个节点,返回最短距离的最大值,否则返回-1
    return cnt == n ? res : -1;
}
int main() {
    //加快读入
    cin.tie(0), ios::sync_with_stdio(false);

    memset(h, -1, sizeof h);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }

    printf("%d\n", dijkstra());
    return 0;
}


四、Dijkstra+结构体

#include <bits/stdc++.h>
using namespace std;

const int N = 110;
const int M = 2 * 210; //无向边,开两倍

int n, m;
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int d[N];
bool st[N];

//定义结构体
struct Node {
    int id;     //结点ID
    int dist;   //和起点的距离
    bool operator<(const Node &t) const {
        return dist > t.dist; //重载小于号,父节点距离 大于 孔洞节点 距离,则大元素向下,小元素向上,小顶堆
    }
};

int dijkstra() {
    int res = 0, cnt = 0;

    //初始化为无法到达
    memset(d, 0x3f, sizeof d);
    d[1] = 0; // 1号点为出发点,距离为0

    //小顶堆
    priority_queue<Node> q;
    q.push({1, 0});

    while (q.size()) {
        auto u = q.top();
        q.pop();

        if (st[u.id]) continue;
        st[u.id] = true;

        res = max(res, u.dist);
        cnt++; //出队列时统计个数

        //枚举每个出边
        for (int i = h[u.id]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] > d[u.id] + w[i]) {
                d[j] = d[u.id] + w[i];
                q.push({j, d[j]});
            }
        }
    }
    return cnt == n ? res : -1;
}
int main() {
    //加快读入
    cin.tie(0), ios::sync_with_stdio(false);
    memset(h, -1, sizeof h);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    printf("%d\n", dijkstra());
    return 0;
}

五、SPFA解法

#include <bits/stdc++.h>
using namespace std;

const int N = 110;
const int M = 2 * 210; //无向边,开两倍
const int INF = 0x3f3f3f3f;

int n, m;
int h[N], e[M], w[M], ne[M], idx;
void add(int a, int b, int c) {
    e[idx] = b, w[idx] = c, ne[idx] = h[a], h[a] = idx++;
}
int d[N];
bool st[N];

//定义结构体
struct Node {
    int id;   //节点ID
    int dist; //和起点的距离
    bool operator<(const Node &t) const {
        return dist > t.dist; //重载小于号,父节点距离 大于 孔洞节点 距离,则大元素向下,小元素向上,小顶堆
    }
};

// spfa模板
void spfa() {
    queue<int> q;              //队列
    memset(d, 0x3f, sizeof d); //将所有距离初始化为无穷大

    //出发点的距离清零
    d[1] = 0;

    q.push(1);    //出发点入队列
    st[1] = true; //出发点标识已使用
    while (q.size()) {
        int u = q.front();
        q.pop();
        st[u] = false;
        for (int i = h[u]; ~i; i = ne[i]) {
            int j = e[i];
            if (d[j] > d[u] + w[i]) {
                d[j] = d[u] + w[i];
                if (!st[j]) {
                    st[j] = true;
                    q.push(j);
                }
            }
        }
    }
}

// 14 ms
int main() {
    //加快读入
    cin.tie(0), ios::sync_with_stdio(false);
    memset(h, -1, sizeof h);
    cin >> n >> m;
    while (m--) {
        int a, b, c;
        cin >> a >> b >> c;
        add(a, b, c), add(b, a, c);
    }
    spfa();

    int res = 0;
    for (int i = 2; i <= n; i++) {
        if (d[i] == INF) {
            res = -1;
            break;
        }
        res = max(res, d[i]);
    }
    printf("%d\n", res);
    return 0;
}

六、Floyd解法

#include <cstring>
#include <iostream>
#include <algorithm>

using namespace std;

const int N = 110;
const int INF = 0x3f3f3f3f;

int n, m;
int d[N][N];

//	45 ms
int main() {
    //加快读入
    cin.tie(0), ios::sync_with_stdio(false);

    cin >> n >> m;

    //初始化邻接矩阵
    memset(d, 0x3f, sizeof d);
    for (int i = 1; i <= n; i++) d[i][i] = 0;

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

    // 5行代码的Floyd
    for (int k = 1; k <= n; k++)
        for (int i = 1; i <= n; i++)
            for (int j = 1; j <= n; j++)
                d[i][j] = min(d[i][j], d[i][k] + d[k][j]);

    int res = 0;
    for (int i = 1; i <= n; i++)
        if (d[1][i] == INF) {
            res = -1;
            break;
        } else
            res = max(res, d[1][i]);

    printf("%d\n", res);
    return 0;
}
posted @   糖豆爸爸  阅读(169)  评论(0编辑  收藏  举报
相关博文:
阅读排行:
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· Docker 太简单,K8s 太复杂?w7panel 让容器管理更轻松!
历史上的今天:
2018-03-13 《机器学习有意思! 01》- 世界上最简单的机器学习入门
2018-03-13 手工增加Mapping
2018-03-13 github结合TortoiseGit使用sshkey,无需输入账号和密码
2015-03-13 记录一下中间过程2
2015-03-13 记录一下中间过程
Live2D
点击右上角即可分享
微信分享提示