首页 > 试题广场 >

小红送外卖

[编程题]小红送外卖
  • 热度指数:1106 时间限制:C/C++ 2秒,其他语言4秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解
小红在第三新北林市的学园城送外卖,学园城中有非常多的学校,学园城里有一个美食街。小红每次会接一些同一个学校的订单,然后从美食街取餐出发,再骑车将外卖送到学校,最后回到美食街,以此往复。

学园城有 n 个结点, m 条道路,美食街为1号结点,剩下的结点都是学校,保证学园城中所有结点连通。给出小红每次要送外卖的学校,请计算小红最少需要骑行的距离。

输入描述:
第一行输入三个整数 n,m,q(1 \leq n,m,q \leq 10^5) ,分别表示结点数、道路数、送外卖次数。

接下来 m 行,每行输入三个整数 u,v(1 \leq u,v \leq n,u \neq v),w(1 \leq w \leq 10^4) 表示结点 uv 之间有一条长度为 w 的道路。

最后一行输入 q 个整数表示每次送外卖的学校 a(2 \leq a_i \leq n)


输出描述:
输出一个整数表示答案。
示例1

输入

3 2 2
1 2 1
1 3 2
2 3

输出

6

说明

小红先从美食街骑到2号学校,再返回美食街,骑行距离为1+1=2
小红先从美食街骑到3号学校,再返回美食街,骑行距离为2+2=4
因此总共的骑行距离为2+4=6
堆优化的迪杰斯特拉算法求距离。
import sys
from collections import defaultdict
from heapq import *
h = defaultdict(list)
n, m, q = map(int, input().split())
st = [0] * (n + 1)
dist = [10**10] * (n + 1)
for _ in range(m):
    a, b, w = map(int, input().split())
    h[a].append([b, w])
    h[b].append([a, w])
# 堆优化的迪杰斯特拉算法,时间复杂度O(mlogn)
q = []
dist[1] = 0
heappush(q, [0, 1])
while q:
    d, a = q[0]
    heappop(q)
    if st[a]:
        continue
    st[a] = 1
    for b, w in h[a]:
        if not st[b] and(dist[b] > dist[a] + w):
            dist[b] = dist[a] + w
            heappush(q, [dist[a] + w, b])


res = 0
a = list(map(int, input().split()))
for b in a:
    res += dist[b] * 2
print(res)

编辑于 2024-03-16 14:40:46 回复(0)
dijkstra秒了
发表于 2025-03-27 14:15:08 回复(0)

核心思想是堆优化的Dijkstra算法,基本上是模板题,但是要熟练的写出来还是有点难度。注意无向图的节点插入是双向的,另外边的数组要开大一点。

#include 
using namespace std;
typedef pair PII;
typedef long long int ll;
const int N = 2e5+10;
int n;      // 点的数量
int h[N], w[N], e[N], ne[N], idx;       // 邻接表存储所有边
int dist[N];        // 存储所有点到1号点的距离
bool st[N];     // 存储每个点的最短距离是否已确定
// 求1号点到n号点的最短距离,如果不存在,则返回-1
int dijkstra()
{
    memset(dist, 0x3f, sizeof dist);
    dist[1] = 0;
    priority_queue, greater> heap;
    heap.push({0, 1});      // first存储距离,second存储节点编号
    while (heap.size())
    {
        auto t = heap.top();
        heap.pop();
        int ver = t.second, distance = t.first;
        if (st[ver]) continue;
        st[ver] = true;
        for (int i = h[ver]; i != -1; i = ne[i])
        {
            int j = e[i];
            if (dist[j] > distance + w[i])
            {
                dist[j] = distance + w[i];
                heap.push({dist[j], j});
            }
        }
    }
    if (dist[n] == 0x3f3f3f3f) return -1;
    return dist[n];
}
void add(int a, int b, int c)
{
    e[idx] = b, ne[idx] = h[a], w[idx] = c; h[a] = idx ++ ;
}
int main() {
    memset(h, -1, sizeof h);
    int m, q;
    cin >> n >> m >> q;
    while(m--){
        int a, b, c;
        cin >> a >> b >> c;
        add(a,b,c);
        add(b,a,c);
    }
    dijkstra();
    ll sum = 0;
    int idx;
    while(q--){
        cin >> idx;
        sum += dist[idx];
    }
    cout << sum * 2 << endl;
    return 0;
}
// 64 位输出请用 printf("%lld")
发表于 2024-06-21 16:42:01 回复(0)
import heapq


def dijkstra(n, adj, start):
    dist = [float("inf")] * (n + 1)  # 初始化距离数组,所有距离设为无穷大
    dist[start] = 0  # 起点到自身的距离为0
    heap = [(0, start)]  # 最小堆,存储 (距离, 节点) 元组
    while heap:
        d, u = heapq.heappop(heap)  # 弹出当前距离起点最近的节点
        # if d > dist[u]:
        #     continue  # 如果弹出的距离大于已知最短距离,跳过
        for v, w in adj[u]:  # 遍历当前节点的所有邻接节点
            if dist[v] > dist[u] + w:  # 如果通过当前节点到达邻接节点的距离更短
                dist[v] = dist[u] + w  # 更新最短距离
                heapq.heappush(heap, (dist[v], v))  # 将新的距离和节点加入堆中
    return dist


n, m, q = map(int, input().split())  # 读取节点数n,边数m,目标学校数q
adj = [[] for _ in range(n + 1)]  # 初始化邻接表
for _ in range(m):
    u, v, w = map(int, input().split())  # 读取每条边的信息
    adj[u].append((v, w))  # 添加边 u -> v,权重为 w
    adj[v].append((u, w))  # 添加边 v -> u,权重为 w(无向图)
targets = list(map(int, input().split()))  # 读取目标学校列表
dist = dijkstra(n, adj, 1)  # 计算从节点1到所有节点的最短路径
total = sum(2 * dist[t] for t in targets)  # 计算所有目标学校的往返距离之和
print(total)  # 输出总骑行距离

发表于 2025-04-11 12:39:51 回复(0)
堆优化版D算法

#include <functional>
#include <iostream>
#include <vector>
#include <queue>

using namespace std;
using PII = pair<int, int>;
using LL = long long;

int n = 0, m = 0, q = 0;
vector<int> dist;
vector<vector<PII>> adj;

const int INF = 0x3f3f3f3f;

priority_queue<PII, vector<PII>, greater<>> pq;

void solve() {
    dist[1] = 0;

    pq.push({0, 1});

    while (!pq.empty()) {
        auto [dx, x] = pq.top();
        pq.pop();

        if (dx > dist[x]) continue;

        for (auto& [y, w] : adj[x]) {
            int new_dist = dx + w;

            if (new_dist < dist[y]) {
                dist[y] = new_dist;
                pq.push({new_dist, y});
            }
        }
    }
}

int main() {
    cin >> n >> m >> q;

    dist.resize(n + 1, INF); 
    adj.resize(n + 1);

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

        adj[u].push_back({v, w});
        adj[v].push_back({u, w});
    }

    solve();

    LL ans = 0;
    for (int i = 0; i < q; i ++) {
        int a = 0;
        cin >> a;

        ans += 2 * dist[a];
    }

    cout << ans << endl;

    return 0;

}
// 64 位输出请用 printf("%lld")


发表于 2024-11-12 13:31:26 回复(0)