pdd笔试真题-驿站补给最短耗时(C++/Py/Java /Js/Go)

驿站补给最短耗时

拼多多 8月23号笔试 真题 第三题

题目内容

巡检车要从 111 号驿站赶到 CCC 号驿站。沿线共有 CCC 个驿站、EEE 条双向土路。第 iii 条路连接 xix_ixi 与 yiy_iyi,走过要消耗 aia_iai 格能量、耗时 wiw_iwi。

车载电池容量为 BBB,出发时是满的,电量不能超过 BBB。在第 jjj 号驿站可以一格一格充电,每充 1 格耗时 sjs_jsj。请计算从 111 赶到 CCC 的最短时间;若怎么走都到不了,输出 -1

输入描述

第一行三个整数 CCC、EEE、BBB,表示驿站数、土路数与电池容量(2≤C≤1032\le C\le 10^32≤C≤103,1≤E≤1041\le E\le 10^41≤E≤104,1≤B≤1021\le B\le 10^21≤B≤102)。

第二行 CCC 个整数 s1,s2,...,sCs_1,s_2,\ldots,s_Cs1,s2,...,sC(0≤sj≤1020\le s_j\le 10^20≤sj≤102),表示各驿站充 1 格的耗时。

接下来 EEE 行,每行四个整数 xi,yi,ai,wix_i,y_i,a_i,w_ixi,yi,ai,wi(1≤xi,yi≤C1\le x_i,y_i\le C1≤xi,yi≤C,1≤ai≤1021\le a_i\le 10^21≤ai≤102,1≤wi≤1031\le w_i\le 10^31≤wi≤103),描述一条双向土路。

输出描述

输出一个整数:赶到 CCC 号驿站的最短时间。无法到达时输出 -1

样例1

输入

复制代码
4 3 5
2 1 9 3
1 2 3 4
2 3 3 5
3 4 2 6

输出

复制代码
18

说明

出发电量为 5。先走 1→21\to 21→2(耗时 4,剩 2),在 222 号驿站充 3 格(耗时 3),再走 2→3→42\to 3\to 42→3→4(耗时 5+6)。总时间 18。直接在 333 号驿站用单价 9 充电会更慢。

样例2

输入

复制代码
2 1 3
1 1
1 2 4 10

输出

复制代码
-1

说明

唯一一条路要消耗 4 格,超过容量 3,无法通行。

样例3

输入

复制代码
3 2 4
0 5 1
1 2 2 3
2 3 2 4

输出

复制代码
7

说明

111 号驿站充电耗时为 0,但出发已经满电,沿 1→2→31\to 2\to 31→2→3 耗时 3+4=7,不必再充。

数据范围

  • 2≤C≤1032\le C\le 10^32≤C≤103
  • 1≤E≤1041\le E\le 10^41≤E≤104
  • 1≤B≤1021\le B\le 10^21≤B≤102
  • 0≤sj≤1020\le s_j\le 10^20≤sj≤102
  • 1≤ai≤1021\le a_i\le 10^21≤ai≤102
  • 1≤wi≤1031\le w_i\le 10^31≤wi≤103
  • 所有输入均为整数

题解

思路

解题思路: 最短路算法

  1. 本题相比普通单点最短路题型,额外引入了电量限制,加上电量c <= 100可额外增加一个状态。dist[u][c]表示到达u电量为c的最短时间。
  2. 代码基本和普通最短路差不多,额外加入一步,刚到达u并且电量小于B时,可以充电一次,然后重新入队即可。
  3. 算法平均时间复杂度为O((CB + EB) log(CB))

C++

cpp 复制代码
#include<bits/stdc++.h>
using namespace std;
using ll = long long;

struct Edge {
    int to;
    int cost;
    int time;
};

struct Node {
    ll dist;
    int u;
    int battery;

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    int C, E, B;
    cin >> C >> E >> B;
    
    vector<int> s(C + 1);
    for (int i = 1 ; i <= C; i++) {
        cin >> s[i];
    }
    vector<vector<Edge>> graph(C + 1);
    for (int i = 0; i < E; i++) {
        int x, y, a, w;
        cin >> x >> y >> a >> w;

        // 电池容量不足以通过的路,可以直接忽略
        if (a <= B) {
            graph[x].push_back({y, a, w});
            graph[y].push_back({x, a, w});
        }
    } 
    
    const ll INF = LLONG_MAX / 4;
    // dist[u][b]:到达 u,剩余 b 格电量时的最短时间
    vector<vector<ll>> dist(C + 1, vector<ll>(B + 1, INF));
    priority_queue<Node, vector<Node>, greater<Node>> pq;
    // 1 号驿站出发时电量为 B
    dist[1][B] = 0;
    pq.push({0, 1, B});
    
    while (!pq.empty()) {
        auto [d, u, battery] = pq.top();
        pq.pop();
        if (d != dist[u][battery]) {
            continue;
        } 
        // 在当前驿站充 1 格电
        if (battery < B) {
            ll nd = d + s[u];
            // 入队列
            if (nd < dist[u][battery + 1]) {
                dist[u][battery + 1] = nd;
                pq.push({nd, u, battery + 1});
            }
        }        
        // 尝试通行
        for (auto &e : graph[u]) {
            if (battery < e.cost) {
                continue;
            }

            int nextBattery = battery - e.cost;
            ll nd = d + e.time;

            if (nd < dist[e.to][nextBattery]) {
                dist[e.to][nextBattery] = nd;
                pq.push({nd, e.to, nextBattery});
            }
        }        
    }
    
    ll ans = INF;
    for (int battery = 0; battery <= B; battery++) {
        ans = min(ans, dist[C][battery]);
    }
    
    if (ans == INF) {
        cout << -1 << '\n';
    } else {
        cout << ans << '\n';
    }

    return 0;
}

java

java 复制代码
import java.io.*;
import java.util.*;

public class Main {
    static class Edge {
        int to;
        int cost;
        int time;

        Edge(int to, int cost, int time) {
            this.to = to;
            this.cost = cost;
            this.time = time;
        }
    }

    static class Node implements Comparable<Node> {
        long dist;
        int u;
        int battery;

        Node(long dist, int u, int battery) {
            this.dist = dist;
            this.u = u;
            this.battery = battery;
        }

        @Override
        public int compareTo(Node other) {
            return Long.compare(dist, other.dist);
        }
    }

    public static void main(String[] args) throws Exception {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));

        StringTokenizer st = new StringTokenizer(br.readLine());
        int C = Integer.parseInt(st.nextToken());
        int E = Integer.parseInt(st.nextToken());
        int B = Integer.parseInt(st.nextToken());

        int[] s = new int[C + 1];
        st = new StringTokenizer(br.readLine());
        for (int i = 1; i <= C; i++) {
            s[i] = Integer.parseInt(st.nextToken());
        }

        List<Edge>[] graph = new ArrayList[C + 1];
        for (int i = 1; i <= C; i++) {
            graph[i] = new ArrayList<>();
        }

        for (int i = 0; i < E; i++) {
            st = new StringTokenizer(br.readLine());

            int x = Integer.parseInt(st.nextToken());
            int y = Integer.parseInt(st.nextToken());
            int a = Integer.parseInt(st.nextToken());
            int w = Integer.parseInt(st.nextToken());

            // 电池容量不足以通过的路,可以直接忽略
            if (a <= B) {
                graph[x].add(new Edge(y, a, w));
                graph[y].add(new Edge(x, a, w));
            }
        }

        final long INF = Long.MAX_VALUE / 4;

        // dist[u][b]:到达 u,剩余 b 格电量时的最短时间
        long[][] dist = new long[C + 1][B + 1];
        for (int i = 1; i <= C; i++) {
            Arrays.fill(dist[i], INF);
        }

        PriorityQueue<Node> pq = new PriorityQueue<>();

        // 1 号驿站出发时电量为 B
        dist[1][B] = 0;
        pq.offer(new Node(0, 1, B));

        while (!pq.isEmpty()) {
            Node cur = pq.poll();

            long d = cur.dist;
            int u = cur.u;
            int battery = cur.battery;

            if (d != dist[u][battery]) {
                continue;
            }

            // 在当前驿站充 1 格电
            if (battery < B) {
                long nd = d + s[u];

                // 入队列
                if (nd < dist[u][battery + 1]) {
                    dist[u][battery + 1] = nd;
                    pq.offer(new Node(nd, u, battery + 1));
                }
            }

            // 尝试通行
            for (Edge e : graph[u]) {
                if (battery < e.cost) {
                    continue;
                }

                int nextBattery = battery - e.cost;
                long nd = d + e.time;

                if (nd < dist[e.to][nextBattery]) {
                    dist[e.to][nextBattery] = nd;
                    pq.offer(new Node(nd, e.to, nextBattery));
                }
            }
        }

        long ans = INF;
        for (int battery = 0; battery <= B; battery++) {
            ans = Math.min(ans, dist[C][battery]);
        }

        if (ans == INF) {
            System.out.println(-1);
        } else {
            System.out.println(ans);
        }
    }
}

python

python 复制代码
import sys
import heapq

# 差分 + 贪心判断
# 这里实际使用的是 Dijkstra + 电量状态

data = list(map(int, sys.stdin.buffer.read().split()))
idx = 0

C = data[idx]
E = data[idx + 1]
B = data[idx + 2]
idx += 3

s = [0] * (C + 1)
for i in range(1, C + 1):
    s[i] = data[idx]
    idx += 1

graph = [[] for _ in range(C + 1)]

for _ in range(E):
    x = data[idx]
    y = data[idx + 1]
    a = data[idx + 2]
    w = data[idx + 3]
    idx += 4

    # 电池容量不足以通过的路,可以直接忽略
    if a <= B:
        graph[x].append((y, a, w))
        graph[y].append((x, a, w))

INF = float('inf')

# dist[u][b]:到达 u,剩余 b 格电量时的最短时间
dist = [[INF] * (B + 1) for _ in range(C + 1)]

pq = []

# 1 号驿站出发时电量为 B
dist[1][B] = 0
heapq.heappush(pq, (0, 1, B))

while pq:
    d, u, battery = heapq.heappop(pq)

    if d != dist[u][battery]:
        continue

    # 在当前驿站充 1 格电
    if battery < B:
        nd = d + s[u]

        # 入队列
        if nd < dist[u][battery + 1]:
            dist[u][battery + 1] = nd
            heapq.heappush(pq, (nd, u, battery + 1))

    # 尝试通行
    for v, cost, time in graph[u]:
        if battery < cost:
            continue

        next_battery = battery - cost
        nd = d + time

        if nd < dist[v][next_battery]:
            dist[v][next_battery] = nd
            heapq.heappush(pq, (nd, v, next_battery))

ans = INF

for battery in range(B + 1):
    ans = min(ans, dist[C][battery])

if ans == INF:
    print(-1)
else:
    print(ans)

javascript

js 复制代码
const readline = require('readline');

const rl = readline.createInterface({
    input: process.stdin,
    output: process.stdout
});

const input = [];

rl.on('line', line => {
    input.push(...line.trim().split(/\s+/));
});

rl.on('close', () => {
    let idx = 0;

    const C = Number(input[idx++]);
    const E = Number(input[idx++]);
    const B = Number(input[idx++]);

    const s = new Array(C + 1).fill(0);

    for (let i = 1; i <= C; i++) {
        s[i] = Number(input[idx++]);
    }

    const graph = Array.from({ length: C + 1 }, () => []);

    for (let i = 0; i < E; i++) {
        const x = Number(input[idx++]);
        const y = Number(input[idx++]);
        const a = Number(input[idx++]);
        const w = Number(input[idx++]);

        // 电池容量不足以通过的路,可以直接忽略
        if (a <= B) {
            graph[x].push([y, a, w]);
            graph[y].push([x, a, w]);
        }
    }

    const INF = Number.MAX_SAFE_INTEGER;

    // dist[u][b]:到达 u,剩余 b 格电量时的最短时间
    const dist = Array.from(
        { length: C + 1 },
        () => new Array(B + 1).fill(INF)
    );

    // 简单二叉堆优先队列
    const pq = [];

    function push(node) {
        pq.push(node);

        let i = pq.length - 1;

        while (i > 0) {
            const parent = Math.floor((i - 1) / 2);

            if (pq[parent][0] <= pq[i][0]) {
                break;
            }

            [pq[parent], pq[i]] = [pq[i], pq[parent]];
            i = parent;
        }
    }

    function pop() {
        const result = pq[0];
        const last = pq.pop();

        if (pq.length > 0) {
            pq[0] = last;

            let i = 0;

            while (true) {
                let smallest = i;
                const left = i * 2 + 1;
                const right = i * 2 + 2;

                if (left < pq.length && pq[left][0] < pq[smallest][0]) {
                    smallest = left;
                }

                if (right < pq.length && pq[right][0] < pq[smallest][0]) {
                    smallest = right;
                }

                if (smallest === i) {
                    break;
                }

                [pq[i], pq[smallest]] = [pq[smallest], pq[i]];
                i = smallest;
            }
        }

        return result;
    }

    // 1 号驿站出发时电量为 B
    dist[1][B] = 0;
    push([0, 1, B]);

    while (pq.length > 0) {
        const [d, u, battery] = pop();

        if (d !== dist[u][battery]) {
            continue;
        }

        // 在当前驿站充 1 格电
        if (battery < B) {
            const nd = d + s[u];

            // 入队列
            if (nd < dist[u][battery + 1]) {
                dist[u][battery + 1] = nd;
                push([nd, u, battery + 1]);
            }
        }

        // 尝试通行
        for (const edge of graph[u]) {
            const [v, cost, time] = edge;

            if (battery < cost) {
                continue;
            }

            const nextBattery = battery - cost;
            const nd = d + time;

            if (nd < dist[v][nextBattery]) {
                dist[v][nextBattery] = nd;
                push([nd, v, nextBattery]);
            }
        }
    }

    let ans = INF;

    for (let battery = 0; battery <= B; battery++) {
        ans = Math.min(ans, dist[C][battery]);
    }

    if (ans === INF) {
        console.log(-1);
    } else {
        console.log(ans);
    }
});

Go

go 复制代码
package main

import (
	"bufio"
	"container/heap"
	"fmt"
	"os"
)

type Edge struct {
	to   int
	cost int
	time int
}

type Node struct {
	dist    int64
	u       int
	battery int
}

type PriorityQueue []Node

func (pq PriorityQueue) Len() int {
	return len(pq)
}

func (pq PriorityQueue) Less(i, j int) bool {
	return pq[i].dist < pq[j].dist
}

func (pq PriorityQueue) Swap(i, j int) {
	pq[i], pq[j] = pq[j], pq[i]
}

func (pq *PriorityQueue) Push(x interface{}) {
	*pq = append(*pq, x.(Node))
}

func (pq *PriorityQueue) Pop() interface{} {
	old := *pq
	n := len(old)
	x := old[n-1]
	*pq = old[:n-1]
	return x
}

func main() {
	in := bufio.NewReader(os.Stdin)
	out := bufio.NewWriter(os.Stdout)
	defer out.Flush()

	var C, E, B int
	fmt.Fscan(in, &C, &E, &B)

	s := make([]int, C+1)

	for i := 1; i <= C; i++ {
		fmt.Fscan(in, &s[i])
	}

	graph := make([][]Edge, C+1)

	for i := 0; i < E; i++ {
		var x, y, a, w int
		fmt.Fscan(in, &x, &y, &a, &w)

		// 电池容量不足以通过的路,可以直接忽略
		if a <= B {
			graph[x] = append(graph[x], Edge{y, a, w})
			graph[y] = append(graph[y], Edge{x, a, w})
		}
	}

	const INF int64 = 1 << 62

	// dist[u][b]:到达 u,剩余 b 格电量时的最短时间
	dist := make([][]int64, C+1)

	for i := 1; i <= C; i++ {
		dist[i] = make([]int64, B+1)

		for j := 0; j <= B; j++ {
			dist[i][j] = INF
		}
	}

	pq := &PriorityQueue{}
	heap.Init(pq)

	// 1 号驿站出发时电量为 B
	dist[1][B] = 0
	heap.Push(pq, Node{0, 1, B})

	for pq.Len() > 0 {
		cur := heap.Pop(pq).(Node)

		d := cur.dist
		u := cur.u
		battery := cur.battery

		if d != dist[u][battery] {
			continue
		}

		// 在当前驿站充 1 格电
		if battery < B {
			nd := d + int64(s[u])

			// 入队列
			if nd < dist[u][battery+1] {
				dist[u][battery+1] = nd
				heap.Push(pq, Node{nd, u, battery + 1})
			}
		}

		// 尝试通行
		for _, e := range graph[u] {
			if battery < e.cost {
				continue
			}

			nextBattery := battery - e.cost
			nd := d + int64(e.time)

			if nd < dist[e.to][nextBattery] {
				dist[e.to][nextBattery] = nd
				heap.Push(pq, Node{nd, e.to, nextBattery})
			}
		}
	}

	var ans int64 = INF

	for battery := 0; battery <= B; battery++ {
		if dist[C][battery] < ans {
			ans = dist[C][battery]
		}
	}

	if ans == INF {
		fmt.Fprintln(out, -1)
	} else {
		fmt.Fprintln(out, ans)
	}
}
相关推荐
无限码力23 天前
拼多多笔试真题-评价展示序列(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多机试·拼多多技术岗笔试·拼多多笔试·拼多多技术岗笔试真题
无限码力23 天前
拼多多笔试真题-多多送快递(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多机试·拼多多笔试·拼多多技术岗真题
无限码力24 天前
拼多多笔试真题-多多的告警网络(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多笔试·拼多多技术岗笔试真题
无限码力1 个月前
拼多多笔试真题-多多的GPU批处理调度(C++/Py/Java /Js/Go)
拼多多·pdd·拼多多笔试真题·拼多多机试·拼多多笔试·拼多多技术岗笔试真题
无限码力1 个月前
拼多多笔试真题-多多的灰度发布(C++/Py/Java /Js/Go)
拼多多·拼多多机试·拼多多技术岗笔试·拼多多笔试·拼多多技术岗笔试真题
无限码力2 个月前
拼多多笔试真题【多多的特殊三元组】
拼多多·拼多多笔试真题·拼多多笔试题库·拼多多技术岗笔试·pdd笔试笔试真题
无限码力2 个月前
拼多多笔试真题-多多的Boss挑战(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多技术岗笔试题目·拼多多机试·pdd笔试真题
无限码力2 个月前
拼多多笔试真题-多多捕蝇(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多技术岗笔试题目·拼多多机试·pdd笔试真题
无限码力2 个月前
拼多多笔试真题-多多的营救行动(C++/Py/Java /Js/Go)
拼多多·拼多多笔试真题·拼多多笔试题库·拼多多技术岗笔试