1. 概述
小团是美团汽车租赁公司的调度师,某个时刻A和B两地都向该公司提交了租车的订单,分别需要a和b辆汽车。此时,公司的所有车辆都在外运营;通过北斗定位,可以得到所有车辆的位置,小团分别计算了每辆车前往A地和B地完成订单的利润。作为一名精明的调度师,当然是想让公司的利润最大化了。请你帮他分别选择a辆车完成A地的任务,选择b辆车完成B地的任务,使得公司获利最大,每辆车最多只能完成一地的任务。
输入描述
输入第一行包含三个整数n, a, b, 分别表示公司的车辆数量和A, B两地订单所需数量,保证a + b <= n(1 <= n <= 2000),接下来有n行,每行两个正整数x, y, 分别表示该车完成A地任务的利润和完成B地任务的利润。
输出描述
输出仅包含一个正整数,表示公司最大获得的利润和。
样例输入
5 2 2
4 2
3 3
5 4
5 3
1 5
样例输出
18
2. 解题思路
DFS可以做,但肯定是超时的
这里要用到三维的动态规划,还需要优化三维dp数组到二维,并且减除调不必要的循环,才能满足要求。
动态规划
dp[i][j][k]表示前 i 辆车中派出 j 辆到A地,派出 k 辆到B地可以获得的最大利润
状态转移方程
3. 代码及优化
Java
import java.util.Scanner;
public class Main{
public static void main(String[] args) {
Scanner input = new Scanner(System.in);
int n = input.nextInt();
int a = input.nextInt();
int b = input.nextInt();
int[][][] dp = new int[n + 1][a + 1][b + 1];
int[][] profits = new int[n + 1][2];
for (int i = 1; i <= n; i++) {
profits[i][0] = input.nextInt();
profits[i][1] = input.nextInt();
}
for (int i = 1; i <= n; i++) {
//派出i辆车
for (int j = 0; j <= a; j++) {
//向A地派出j辆
for (int k = 0; k <= b; k++) {
//向B地派出k辆
if (j == 0 && k == 0) continue;
if (k == 0) {
//将第i辆车不派出或者派到A地
dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j - 1][k] + profits[i][0]);
}
else if (j == 0) {
//将第i辆车不派出或者派到B地
dp[i][j][k] = Math.max(dp[i - 1][j][k], dp[i - 1][j][k - 1] + profits[i][1]);
}
else {
//将第i辆车不派出或者派到A地或者派到B地
dp[i][j][k] = Math.max(dp[i - 1][j][k],
Math.max(dp[i - 1][j - 1][k] + profits[i][0], dp[i - 1][j][k - 1] + profits[i][1]));
}
}
}
}
int res = dp[n][a][b];
System.out.println(res);
}
}
根据动态规划转移方程可看出,状态 i 只取决于状态 i - 1,因此可以像优化 01背包问题 那样将dp数组降维,降低空间复杂度。
因为状态 i 需要用到状态 i - 1 时的值,如果从小到大计算,则需要的 i - 1时的状态已经被覆盖,