AcWing 1128. 信使

\(AcWing\) \(1128\). 信使

题目传送门

一、题目描述

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

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

指挥部设在 第一个 哨所。

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

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

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

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

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

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

\(2\)\(m+1\) 行:每行三个整数 \(i、j、k\),中间用 \(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 @ 2022-03-13 11:14  糖豆爸爸  阅读(149)  评论(0编辑  收藏  举报
Live2D