#P3520. 第1题-定向越野
          
                        
                                    
                      
        
              - 
          
          
                      1000ms
            
          
                      Tried: 88
            Accepted: 39
            Difficulty: 4
            
          
          
          
                       所属公司 : 
                              京东
                                
            
                        
              时间 :2025年8月30日
                              
                      
          
 
- 
                        算法标签>最短路算法          
 
第1题-定向越野
思路总览
核心想法
把“索道”视为一条权值为 0 的无向边 (A, B)。
用 Floyd-Warshall 求全源最短路,直接得到所有点对最短距离。最终答案就是 dist[s][e]。
复杂度
- 时间:
O(n^3)(n ≤ 100,可承受) - 空间:
O(n^2) 
Python 代码
import sys
def main():
    data = list(map(int, sys.stdin.read().strip().split()))
    it = iter(data)
    n = next(it); m = next(it)
    s = next(it); e = next(it)
    A = next(it); B = next(it)
    INF = 10**15
    d = [[INF]*(n+1) for _ in range(n+1)]
    for i in range(1, n+1):
        d[i][i] = 0
    # 读边,构建无向图
    for _ in range(m):
        u = next(it); v = next(it); w = next(it)
        if w < d[u][v]:
            d[u][v] = d[v][u] = w
    # 加入 0 费用索道
    d[A][B] = d[B][A] = 0
    # Floyd
    for k in range(1, n+1):
        dk = d[k]
        for i in range(1, n+1):
            dik = d[i][k]
            if dik == INF: 
                continue
            di = d[i]
            for j in range(1, n+1):
                v = dik + dk[j]
                if v < di[j]:
                    di[j] = v
    print(d[s][e])
if __name__ == "__main__":
    main()
Java 代码
import java.io.*;
import java.util.*;
public class Main {
    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        StringBuilder sb = new StringBuilder();
        String line;
        while ((line = br.readLine()) != null) {
            line = line.trim();
            if (line.length() == 0) continue;
            sb.append(line).append(' ');
        }
        String[] tok = sb.toString().trim().split("\\s+");
        int idx = 0;
        int n = Integer.parseInt(tok[idx++]);
        int m = Integer.parseInt(tok[idx++]);
        int s = Integer.parseInt(tok[idx++]);
        int e = Integer.parseInt(tok[idx++]);
        int A = Integer.parseInt(tok[idx++]);
        int B = Integer.parseInt(tok[idx++]);
        long INF = (long)1e15;
        long[][] d = new long[n + 1][n + 1];
        for (int i = 1; i <= n; i++) {
            Arrays.fill(d[i], INF);
            d[i][i] = 0;
        }
        // 读入边,更新无向最小权
        for (int i = 0; i < m; i++) {
            int u = Integer.parseInt(tok[idx++]);
            int v = Integer.parseInt(tok[idx++]);
            int w = Integer.parseInt(tok[idx++]);
            if (w < d[u][v]) {
                d[u][v] = w;
                d[v][u] = w;
            }
        }
        // 加入 0 费用索道
        d[A][B] = 0;
        d[B][A] = 0;
        // Floyd
        for (int k = 1; k <= n; k++) {
            for (int i = 1; i <= n; i++) {
                if (d[i][k] == INF) continue;
                for (int j = 1; j <= n; j++) {
                    long v = d[i][k] + d[k][j];
                    if (v < d[i][j]) d[i][j] = v;
                }
            }
        }
        System.out.println(d[s][e]);
    }
}
C++ 代码
#include <bits/stdc++.h>
using namespace std;
int main(){
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int n, m;
    if(!(cin >> n >> m)) return 0;
    int s, e, A, B;
    cin >> s >> e >> A >> B;
    const long long INF = (long long)1e15;
    vector<vector<long long>> d(n+1, vector<long long>(n+1, INF));
    for(int i=1;i<=n;i++) d[i][i]=0;
    for(int i=0;i<m;i++){
        int u,v,w; cin >> u >> v >> w;
        if(w < d[u][v]){
            d[u][v] = w;
            d[v][u] = w; // 无向边
        }
    }
    // 索道 0 费用
    d[A][B] = d[B][A] = 0;
    // Floyd
    for(int k=1;k<=n;k++){
        for(int i=1;i<=n;i++){
            if(d[i][k]==INF) continue;
            for(int j=1;j<=n;j++){
                long long v = d[i][k] + d[k][j];
                if(v < d[i][j]) d[i][j] = v;
            }
        }
    }
    cout << d[s][e] << "\n";
    return 0;
}
        题目内容
某定向越野赛事在一片山区举行,山区内共有n个打卡点(编号为1 ~n),打卡点之间有m条可供通行的山 路,每条山路通行都要花费固定的通行时间(单位:分钟)。赛事要求选手从“起点打卡点”出发,最终到达 “终点打卡点”。 组委会在某两个打卡点A和B之间设置了一条特殊索道,选手可以通过该索道在这两个打卡点之间瞬间往返 (不消耗时间). 请计算选手从起点到终点的最短通行时间(保证存在可达路径)。
输入描述
第一行两个正整数n,m,分别表示打卡点总数和山路数量
第二行两个正整数,分别表示“起点打卡点”和“终点打卡点”的编号。
第三行两个正整数,分别表示设有特殊索道的两个打卡点的编号。
接下来m 行,每行三个正整数u,v,t,分别表示打卡点 u和v之间有一条山路,双向通行,通过该山 路需要消耗t分钟。
1<=n<=100,1<=m<=2∗n,每条道路的时间花费在[1,10]之间。
输出描述
一个整数表示最短通行时间。
样例1
输入
6 5
2 6 
3 5
2 3 3
3 4 2
4 5 1
5 6 4
2 4 5
输出
7