[USACO09OCT] Heat Wave G

GitHub跳转原题关系图返回列表

标准正权无向图单源最短路,直接从起点 s 跑一次 Dijkstra,输出到终点 t 的距离即可。

OJ: luogu

题目 ID: P1339

难度:普及-

标签:最短路图论

日期: 2026-06-20 03:21

题意

给一张带正边权的无向图,要求输出从 st 的最短路长度。

思路

先看一个最直接的小数据暴力:

cpp
// brute.cpp:Floyd 求任意两点最短路。
// 适合小数据对拍,也能直接帮助理解题意。
#include <bits/stdc++.h>
using namespace std;

const int MAXN = 105;
const long long INF = (1LL << 60);

int n, m, s, t;
long long dist_arr[MAXN][MAXN];

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m >> s >> t;

    for (int i = 1; i <= n; i++) {
        for (int j = 1; j <= n; j++) {
            if (i == j) {
                dist_arr[i][j] = 0;
            }
            else {
                dist_arr[i][j] = INF;
            }
        }
    }

    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        if (w < dist_arr[u][v]) {
            dist_arr[u][v] = w;
            dist_arr[v][u] = w;
        }
    }

    for (int k = 1; k <= n; k++) {
        for (int i = 1; i <= n; i++) {
            for (int j = 1; j <= n; j++) {
                if (dist_arr[i][k] + dist_arr[k][j] < dist_arr[i][j]) {
                    dist_arr[i][j] = dist_arr[i][k] + dist_arr[k][j];
                }
            }
        }
    }

    cout << dist_arr[s][t] << '\n';

    return 0;
}

暴力做法可以用 Floyd:

  1. 先求任意两点最短路
  2. 最后直接输出 dist[s][t]

但这题其实就是最标准的单源最短路模板题。

题目特征很明确:

  • 无向图
  • 边权都是正数
  • 只问一对起点终点

所以直接从 s 出发跑一次 Dijkstra 即可。

dist[x] 表示从 sx 的最短路,那么答案就是:

  • dist[t]

代码

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

const int MAXN = 2500 + 5;
const int MAXM = 6200 * 2 + 5;
const long long INF = (1LL << 60);

struct Node {
    int u;
    long long dist;

    bool operator < (const Node &other) const {
        return dist > other.dist;
    }
};

int n, m, s, t;
int head[MAXN], to[MAXM], nxt[MAXM], weight_arr[MAXM], edge_cnt;
long long dist_arr[MAXN];
bool vis[MAXN];

void init_graph() {
    edge_cnt = 0;
    for (int i = 1; i <= n; i++) {
        head[i] = 0;
    }
}

void add_edge(int u, int v, int w) {
    edge_cnt++;
    to[edge_cnt] = v;
    weight_arr[edge_cnt] = w;
    nxt[edge_cnt] = head[u];
    head[u] = edge_cnt;
}

void dijkstra(int start) {
    for (int i = 1; i <= n; i++) {
        dist_arr[i] = INF;
        vis[i] = false;
    }

    priority_queue<Node> pq;
    dist_arr[start] = 0;
    pq.push({start, 0});

    while (!pq.empty()) {
        Node cur = pq.top();
        pq.pop();

        int u = cur.u;
        if (vis[u]) {
            continue;
        }
        vis[u] = true;

        for (int i = head[u]; i != 0; i = nxt[i]) {
            int v = to[i];
            long long nd = dist_arr[u] + weight_arr[i];
            if (nd < dist_arr[v]) {
                dist_arr[v] = nd;
                pq.push({v, nd});
            }
        }
    }
}

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);

    cin >> n >> m >> s >> t;
    init_graph();

    for (int i = 1; i <= m; i++) {
        int u, v, w;
        cin >> u >> v >> w;
        add_edge(u, v, w);
        add_edge(v, u, w);
    }

    dijkstra(s);
    cout << dist_arr[t] << '\n';

    return 0;
}

复杂度

堆优化 Dijkstra 的复杂度:

  • O((N+M)logN)O((N + M) \log N)

空间复杂度:

  • O(N+M)O(N + M)

总结

这题没有额外建模,重点就是识别:

  • 单源
  • 正边权
  • 稀疏图

一旦看到这三个信号,基本就应该直接想到堆优化 Dijkstra。