Day59-图论,卡码网47,94

  1. 参加科学大会(第六期模拟笔试)
  • 题目描述:小明是一位科学家,他需要参加一场重要的国际科学大会,以展示自己的最新研究成果。小明的起点是第一个车站,终点是最后一个车站。然而,途中的各个车站之间的道路状况、交通拥堵程度以及可能的自然因素(如天气变化)等不同,这些因素都会影响每条路径的通行时间。小明希望能选择一条花费时间最少的路线,以确保他能够尽快到达目的地。

  • 输入描述:第一行包含两个正整数,第一个正整数 N 表示一共有 N 个公共汽车站,第二个正整数 M 表示有 M 条公路。 接下来为 M 行,每行包括三个整数,S、E 和 V,代表了从 S 车站可以单向直达 E 车站,并且需要花费 V 单位的时间。

  • 输出描述:输出一个整数,代表小明从起点到终点所花费的最小时间。

  • 输入示例

  • 7 9

  • 1 2 1

  • 1 3 4

  • 2 3 2

  • 2 4 5

  • 3 4 2

  • 4 5 3

  • 2 6 4

  • 5 7 4

  • 6 7 9

  • 输出示例

  • 12


  • 思路
  • 堆优化细节,思路依然是 dijkstra 三部曲:
    • 第一步,选源点到哪个节点近且该节点未被访问过
    • 第二步,该最近节点被标记访问过
    • 第三步,更新非访问节点到源点的距离(即更新minDist数组)
    • 只不过之前是 通过遍历节点来遍历边,通过两层for循环来寻找距离源点最近节点。 这次直接遍历边,且通过堆来对边进行排序,达到直接选择距离源点最近节点。有了小顶堆自动对边的权值排序,只需要直接从 堆里取堆顶元素(小顶堆中,最小的权值在上面),就可以取到离源点最近的节点了
class PriorityQueue {
    constructor(comparator) {
        this.heap = [];
        this.comparator = comparator || ((a, b) => a[1] - b[1]);
    }

    push(item) {
        this.heap.push(item);
        this.heap.sort(this.comparator);
    }

    pop() {
        return this.heap.shift();
    }

    top() {
        return this.heap[0];
    }

    empty() {
        return this.heap.length === 0;
    }
}

async function main() {
    const readline = require('readline');
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    const lines = [];
    for await (const line of rl) {
        lines.push(line);
    }

    // 解析输入
    const [n, m] = lines[0].split(' ').map(Number);
    
    // 构建邻接表
    const grid = new Array(n + 1).fill().map(() => []);
    
    for (let i = 1; i <= m; i++) {
        const [p1, p2, val] = lines[i].split(' ').map(Number);
        grid[p1].push({ to: p2, val });
    }

    const start = 1; // 起点
    const end = n;   // 终点

    // 存储从源点到每个节点的最短距离
    const minDist = new Array(n + 1).fill(Number.MAX_SAFE_INTEGER);
    
    // 记录顶点是否被访问过
    const visited = new Array(n + 1).fill(false);
    
    // 优先队列 (小顶堆)
    const pq = new PriorityQueue((a, b) => a[1] - b[1]);

    // 初始化队列,源点到源点的距离为0
    pq.push([start, 0]);
    minDist[start] = 0;

    while (!pq.empty()) {
        // 1. 获取当前距离起点最近的节点
        const [currentNode, currentDist] = pq.pop();

        if (visited[currentNode]) continue;

        // 2. 标记当前节点为已访问
        visited[currentNode] = true;

        // 3. 更新邻接节点的最短距离
        for (const edge of grid[currentNode]) {
            const neighbor = edge.to;
            const weight = edge.val;
            
            if (!visited[neighbor] && minDist[currentNode] + weight < minDist[neighbor]) {
                minDist[neighbor] = minDist[currentNode] + weight;
                pq.push([neighbor, minDist[neighbor]]);
            }
        }
    }

    // 输出结果
    if (minDist[end] === Number.MAX_SAFE_INTEGER) {
        console.log(-1); // 不能到达终点
    } else {
        console.log(minDist[end]); // 到达终点的最短路径长度
    }
}

main();


  1. 城市间货物运输 I
  • 题目描述:某国为促进城市间经济交流,决定对货物运输提供补贴。共有 n 个编号为 1 到 n 的城市,通过道路网络连接,网络中的道路仅允许从某个城市单向通行到另一个城市,不能反向通行。网络中的道路都有各自的运输成本和政府补贴,道路的权值计算方式为:运输成本 - 政府补贴。权值为正表示扣除了政府补贴后运输货物仍需支付的费用;权值为负则表示政府的补贴超过了支出的运输成本,实际表现为运输过程中还能赚取一定的收益。请找出从城市 1 到城市 n 的所有可能路径中,综合政府补贴后的最低运输成本。如果最低运输成本是一个负数,它表示在遵循最优路径的情况下,运输过程中反而能够实现盈利。城市 1 到城市 n 之间可能会出现没有路径的情况,同时保证道路网络中不存在任何负权回路。

  • 输入描述:第一行包含两个正整数,第一个正整数 n 表示该国一共有 n 个城市,第二个整数 m 表示这些城市中共有 m 条道路。 接下来为 m 行,每行包括三个整数,s、t 和 v,表示 s 号城市运输货物到达 t 号城市,道路权值为 v (单向图)。

  • 输出描述:如果能够从城市 1 到连通到城市 n, 请输出一个整数,表示运输成本。如果该整数是负数,则表示实现了盈利。如果从城市 1 没有路径可达城市 n,请输出 "unconnected"。

  • 输入示例

  • 6 7

  • 5 6 -2

  • 1 2 1

  • 5 3 1

  • 2 5 2

  • 2 4 -3

  • 4 6 4

  • 1 3 5

  • 输出示例

  • 1


  • 思路
  • Bellman_ford算法的核心思想是 对所有边进行松弛n-1次操作(n为节点数量),从而求得目标最短路if (minDist[B] > minDist[A] + value) minDist[B] = minDist[A] + value。使用minDist数组来表达 起点到各个节点的最短距离,例如minDist[3] = 5 表示起点到达节点3 的最小距离为5。对所有边松弛一次,相当于计算 起点到达 与起点一条边相连的节点 的最短距离。对所有边松弛 n-1 次 就一定能得到 起点到达 终点的最短距离。
async function main() {
    const readline = require('readline');
    const rl = readline.createInterface({
        input: process.stdin,
        output: process.stdout
    });

    const lines = [];
    for await (const line of rl) {
        lines.push(line);
    }

    // 解析输入
    const [n, m] = lines[0].split(' ').map(Number);
    
    // 存储所有边
    const edges = [];
    
    for (let i = 1; i <= m; i++) {
        const [p1, p2, val] = lines[i].split(' ').map(Number);
        edges.push([p1, p2, val]);
    }

    const start = 1; // 起点
    const end = n;   // 终点

    // 初始化最短距离数组
    const minDist = new Array(n + 1).fill(Number.MAX_SAFE_INTEGER);
    minDist[start] = 0; // 起点到自身的距离为0

    // Bellman-Ford算法核心
    for (let i = 1; i < n; i++) { // 最多进行n-1次松弛
        let updated = false;
        
        for (const [from, to, price] of edges) {
            // 松弛操作
            if (minDist[from] !== Number.MAX_SAFE_INTEGER && 
                minDist[to] > minDist[from] + price) {
                minDist[to] = minDist[from] + price;
                updated = true;
            }
        }
        
        // 如果没有更新,提前终止
        if (!updated) break;
    }

    // 输出结果
    if (minDist[end] === Number.MAX_SAFE_INTEGER) {
        console.log('unconnected'); // 不能到达终点
    } else {
        console.log(minDist[end]); // 到达终点的最短路径
    }
}

main();




参考&感谢各路大神

posted @ 2025-07-25 09:40  安静的嘶吼  阅读(9)  评论(0)    收藏  举报