京东技术岗笔试真题【星际快递】多语言题解

星际快递(C++/Py/Java /Js/Go)题解

京东技术岗 0314笔试 第一题

题目内容

星际快递公司有 NNN 个包裹需要派送,每个包裹有两种派送方式:

  1. 常规派送(消耗较多燃料)
  2. 虫洞派送(使用一个虫洞通行证,可以消耗较少燃料的情况下完成派送)
    当前快递飞船携带了 XXX 单位的燃料和 YYY 张虫洞通行证。
    星际快递公司想要计算,在优先派送尽可能多包裹的情况下,最小的燃料消耗是多少,请你帮助他们计算一下。

输入描述

第一行三个整数 N,X,YN,X,YN,X,Y ,分别表示包裹数量,携带燃料量以及通行证数量。

接下来 NNN 行,每行两个整数,表示各个包裹常规派送和虫洞派送分别需要的燃料量。

数据范围:

  • 1≤N≤1001 ≤ N ≤ 1001≤N≤100
  • 1≤X≤50001 ≤ X ≤ 50001≤X≤5000
  • 1≤Y≤501 ≤ Y ≤ 501≤Y≤50
  • 每个包裹常规派送和虫洞派送的燃料消耗均介于 1,501, 501,50 之间。

输出描述

一行,两个整数,空格分开,表示最多可派送的包裹数量及对应的最小燃料消耗。

样例1

输入

复制代码
3 20 1
8 5
7 4
10 6

输出

复制代码
2 12

样例2

输入

复制代码
4 25 2
10 6
8 5
12 7
9 6

输出

复制代码
3 20

题解和思路

思路

实现思路:动态规划

  1. 定义dp数组其中,dp[i][j] 表示完成j个运输,使用k个通行费所需最小燃料。初始全部设置为不可达值,额外定义dp[0][0] = 1
  2. 从前往后枚举运输任务,从大到小枚举完成任务数 j ,以及从大到小枚举通行证使用数 k,如果dp[j][k]可达,状态转移方程为:
    1. 常规配送:dp[j + 1][k] = min(dp[j + 1][k], dp[j][k] + a);
    2. 虫洞运输: dp[j + 1][k + 1] = min(dp[j + 1][k + 1], dp[j][k] + b);
  3. 按照3的逻辑处理之后,最终可以确定最大运输数量和使用燃料的数量。
  4. 上述代码的时间复杂度为O(N X Y)

C++

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

int main() {
    ios::sync_with_stdio(false);
    cin.tie(nullptr);
    
    int N, X, Y;
    cin >> N >> X >> Y;
    vector<int> A(N), B(N);
    for (int i = 0; i < N; i++) {
        cin >> A[i] >> B[i];
    }
    // dp[j][k] 完成j个运输,使用k个通行费所需最小燃料
    vector<vector<int>> dp(N + 1, vector<int>(Y + 1, INT_MAX));
    dp[0][0] = 0;
    for (int i = 0; i < N; i++) {
        int a = A[i], b = B[i];
        for (int j = N - 1; j >= 0; j--) {
            for (int k = Y; k >=0; k--) {
                if (dp[j][k] == INT_MAX) {
                    continue;
                }
                // 常规
                dp[j + 1][k] = min(dp[j + 1][k], dp[j][k] + a);
                // 冲动
                if (k + 1 <= Y) {
                    dp[j + 1][k + 1] = min(dp[j + 1][k + 1], dp[j][k] + b);
                }
            }
        }
    }

    int bestCnt = 0, minFule = 0;
    for (int j = N; j >= 0; --j) {
        int cur = INT_MAX;
        for (int k = 0; k <= Y; ++k) cur = min(cur, dp[j][k]);
        if (cur <= X) {
            bestCnt = j;
            minFule = cur;
            break;
        }
    }
    cout << bestCnt << " " << minFule << endl;
    return 0;
}

Java

java 复制代码
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.StringTokenizer;

public class Main {
    static final int INF = Integer.MAX_VALUE;

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

        int N = Integer.parseInt(st.nextToken());
        int X = Integer.parseInt(st.nextToken());
        int Y = Integer.parseInt(st.nextToken());

        int[] A = new int[N];
        int[] B = new int[N];

        for (int i = 0; i < N; i++) {
            st = new StringTokenizer(br.readLine());
            A[i] = Integer.parseInt(st.nextToken());
            B[i] = Integer.parseInt(st.nextToken());
        }

        // dp[j][k] 完成j个运算,使用k个通行费所需最小燃料
        int[][] dp = new int[N + 1][Y + 1];
        for (int i = 0; i <= N; i++) {
            for (int j = 0; j <= Y; j++) {
                dp[i][j] = INF;
            }
        }

        dp[0][0] = 0;

        for (int i = 0; i < N; i++) {
            int a = A[i], b = B[i];
            for (int j = N - 1; j >= 0; j--) {
                for (int k = Y; k >= 0; k--) {
                    if (dp[j][k] == INF) {
                        continue;
                    }
                    // 常规
                    dp[j + 1][k] = Math.min(dp[j + 1][k], dp[j][k] + a);

                    // 冲动
                    if (k + 1 <= Y) {
                        dp[j + 1][k + 1] = Math.min(dp[j + 1][k + 1], dp[j][k] + b);
                    }
                }
            }
        }

        int bestCnt = 0, minFuel = 0;
        for (int j = N; j >= 0; j--) {
            int cur = INF;
            for (int k = 0; k <= Y; k++) {
                cur = Math.min(cur, dp[j][k]);
            }
            if (cur <= X) {
                bestCnt = j;
                minFuel = cur;
                break;
            }
        }

        System.out.println(bestCnt + " " + minFuel);
    }
}

python

python 复制代码
INF = float("inf")

N, X, Y = map(int, input().split())

A = [0] * N
B = [0] * N

for i in range(N):
    A[i], B[i] = map(int, input().split())

# dp[j][k] 完成j个运算,使用k个通行费所需最小燃料
dp = [[INF] * (Y + 1) for _ in range(N + 1)]
dp[0][0] = 0

for i in range(N):
    a, b = A[i], B[i]
    for j in range(N - 1, -1, -1):
        for k in range(Y, -1, -1):
            if dp[j][k] == INF:
                continue

            # 常规
            dp[j + 1][k] = min(dp[j + 1][k], dp[j][k] + a)

            # 冲动
            if k + 1 <= Y:
                dp[j + 1][k + 1] = min(dp[j + 1][k + 1], dp[j][k] + b)

bestCnt = 0
minFuel = 0

for j in range(N, -1, -1):
    cur = min(dp[j])
    if cur <= X:
        bestCnt = j
        minFuel = cur
        break

print(bestCnt, minFuel)

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);
});

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

    const [N, X, Y] = input[idx++].split(" ").map(Number);

    const A = new Array(N);
    const B = new Array(N);

    for (let i = 0; i < N; i++) {
        const [a, b] = input[idx++].split(" ").map(Number);
        A[i] = a;
        B[i] = b;
    }

    // dp[j][k] 完成j个运算,使用k个通行费所需最小燃料
    const dp = Array.from({ length: N + 1 }, () => Array(Y + 1).fill(Number.MAX_SAFE_INTEGER));
    dp[0][0] = 0;

    for (let i = 0; i < N; i++) {
        const a = A[i], b = B[i];
        for (let j = N - 1; j >= 0; j--) {
            for (let k = Y; k >= 0; k--) {
                if (dp[j][k] === Number.MAX_SAFE_INTEGER) {
                    continue;
                }

                // 常规
                dp[j + 1][k] = Math.min(dp[j + 1][k], dp[j][k] + a);

                // 冲动
                if (k + 1 <= Y) {
                    dp[j + 1][k + 1] = Math.min(dp[j + 1][k + 1], dp[j][k] + b);
                }
            }
        }
    }

    let bestCnt = 0;
    let minFuel = 0;

    for (let j = N; j >= 0; j--) {
        let cur = Number.MAX_SAFE_INTEGER;
        for (let k = 0; k <= Y; k++) {
            cur = Math.min(cur, dp[j][k]);
        }
        if (cur <= X) {
            bestCnt = j;
            minFuel = cur;
            break;
        }
    }

    console.log(bestCnt + " " + minFuel);
});

Go

go 复制代码
package main

import (
	"bufio"
	"fmt"
	"math"
	"os"
)

func min(a, b int) int {
	if a < b {
		return a
	}
	return b
}

func main() {
	in := bufio.NewReader(os.Stdin)

	var N, X, Y int
	fmt.Fscan(in, &N, &X, &Y)

	A := make([]int, N)
	B := make([]int, N)

	for i := 0; i < N; i++ {
		fmt.Fscan(in, &A[i], &B[i])
	}

	// dp[j][k] 完成j个运算,使用k个通行费所需最小燃料
	dp := make([][]int, N+1)
	for i := 0; i <= N; i++ {
		dp[i] = make([]int, Y+1)
		for j := 0; j <= Y; j++ {
			dp[i][j] = math.MaxInt32
		}
	}

	dp[0][0] = 0

	for i := 0; i < N; i++ {
		a, b := A[i], B[i]
		for j := N - 1; j >= 0; j-- {
			for k := Y; k >= 0; k-- {
				if dp[j][k] == math.MaxInt32 {
					continue
				}

				// 常规
				dp[j+1][k] = min(dp[j+1][k], dp[j][k]+a)

				// 冲动
				if k+1 <= Y {
					dp[j+1][k+1] = min(dp[j+1][k+1], dp[j][k]+b)
				}
			}
		}
	}

	bestCnt := 0
	minFuel := 0

	for j := N; j >= 0; j-- {
		cur := math.MaxInt32
		for k := 0; k <= Y; k++ {
			cur = min(cur, dp[j][k])
		}
		if cur <= X {
			bestCnt = j
			minFuel = cur
			break
		}
	}

	fmt.Println(bestCnt, minFuel)
}