首页 > 试题广场 >

小团的车辆调度

[编程题]小团的车辆调度
  • 热度指数:1871 时间限制:C/C++ 1秒,其他语言2秒 空间限制:C/C++ 256M,其他语言512M
  • 算法知识视频讲解

       小团是美团汽车租赁公司的调度师,某个时刻AB两地都向该公司提交了租车的订单,分别需要ab辆汽车。此时,公司的所有车辆都在外运营,通过北斗定位,可以得到所有车辆的位置,小团分别计算了每辆车前往A地和B地完成订单的利润。作为一名精明的调度师,当然是想让公司的利润最大化了。

      请你帮他分别选择a辆车完成A地的任务,选择b辆车完成B地的任务。使得公司获利最大,每辆车最多只能完成一地的任务。

 


输入描述:

输入第一行包含三个整数n,a,b,分别表示公司的车辆数量和A,B两地订单所需数量,保证a+b<=n。(1<=n<=2000)

接下来有n行,每行两个正整数x,y,分别表示该车完成A地任务的利润和B地任务的利润。

 



输出描述:
输出仅包含一个正整数,表示公司最大获得的利润和。
示例1

输入

5 2 2
4 2
3 3
5 4
5 3
1 5

输出

18
#include<iostream>
#include<cstring>
using namespace std;


int main(  ) {
        
     int n,a,b;
     cin>>n>>a>>b;

     int tab[a+1][b+1];
     memset(tab,0,sizeof(tab));
     int fx,fy;
       for(int i=1;i<=n;i++){
            cin>>fx>>fy;
           for(int j=min(a, i);j>= 0;j--){//j>=Math.max(0, a - n + i)  a+b<n , 剩余的车要有单接 max(0, a - n + i)
               for(int k= min(b, i-j);k>= 0;k--){//max(0, a +b - n + i-j)
                   int r1=tab[j][k];
                   if(j>=1){
                       int r2=tab[j-1][k]+fx  ;
                       if(r2>r1)r1=r2;
                   }
                   if(k>=1){
                       int r3=tab[j][k-1]+fy  ;
                       if(r3>r1)r1=r3;
                   }
                   tab[j][k]=r1;
               }
           }
          
       }

       cout<<tab[a][b] ;
      
   
   
}



发表于 2021-03-21 19:55:08 回复(0)
#include<bits/stdc++.h>
using namespace std;
int n,a,b;
int main(){
    scanf("%d%d%d",&n,&a,&b);
    int dp[a+1][b+1];
    memset(dp, 0, sizeof(dp));
    int x,y;
    for(int k=1;k<=n;k++){
       scanf("%d%d",&x,&y);
        for(int i=min(a,k);i>=0;i--){
            for(int j=min(b,k-i);j>=0;j--){
                //使用max()比较的话会超时
                if(j>0&&dp[i][j]<dp[i][j-1]+y) 
                    dp[i][j]=dp[i][j-1]+y;
                if(i>0&&dp[i][j]<dp[i-1][j]+x)
                    dp[i][j]=dp[i-1][j]+x;
            }
        }
    }
    printf("%d\n",dp[a][b]);
}

发表于 2022-08-19 10:23:41 回复(0)
三维背包问题超内存,将三维优化到二维又超时了,求大佬再优化优化😂
dp[j][k]表示前 辆车派 辆到A地,派 辆车到B地所得的最大利润,x表示第 辆车派往A地带来的利润,y表示第 辆车派往B地带来的利润。
它可以由以下三种状态转移过来:
(1) 第 i 辆车不使用:dp[j][k] = dp[j][k]
(2) 第 i 辆车派往A地:dp[j][k] = dp[j - 1][k] + x
(3) 第 i 辆车派往B地:dp[j][k] = dp[j][k - 1] + y
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().trim().split(" ");
        int n = Integer.parseInt(params[0]);
        int a = Integer.parseInt(params[1]);
        int b = Integer.parseInt(params[2]);
        int x, y;
        // 循环到i时,dp[j][k]表示前i辆车中派出j辆到A地,派出k辆到B地可以获得的最大利润
        int[][] dp = new int[a + 1][b + 1];
        for(int i = 1; i <= n; i++) {
            params = br.readLine().trim().split(" ");
            x = Integer.parseInt(params[0]);
            y = Integer.parseInt(params[1]);
            for(int j = Math.min(a, i); j >= 0; j--) {
                for(int k = Math.min(b, i - j); k >= 0; k--) {
                    if(j == 0 && k == 0) continue;
                    if(k == 0){
                        // B地的车够了,第i辆车不派出或者派到A地
                        dp[j][k] = Math.max(dp[j][k], dp[j - 1][k] + x);
                    }else if (j == 0){
                        // A地的车够了,第i辆车不派出或者派到B地
                        dp[j][k] = Math.max(dp[j][k], dp[j][k - 1] + y);
                    }else{
                        // 此时第i辆车可以选择往A地派也可以选择往B地派或不派
                        dp[j][k] = Math.max(dp[j][k], Math.max(dp[j - 1][k] + x, dp[j][k - 1] + y));
                    }
                }
            }
        }
        System.out.println(dp[a][b]);
    }
}
第二层循环的起点表示:如果 小于a,是不可能派出a辆车的,如果 大于a,也不可能派出超过a辆车去A地,相当于剪枝。
第三层循环的起点表示:前i辆车最多往B地派 i - j 辆(因为有j辆已经派往了A地),而 i - j 又不能超过b
看试卷得分应该是AC了80%,剩下的超时了
-------------------------------------------------- 分割线 --------------------------------------------------
感谢评论区大佬的优化意见,这样就可以AC了
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.io.IOException;

public class Main{
    public static void main(String[] args) throws IOException {
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        String[] params = br.readLine().trim().split(" ");
        int n = Integer.parseInt(params[0]);
        int a = Integer.parseInt(params[1]);
        int b = Integer.parseInt(params[2]);
        int x, y;
        // 循环到i时,dp[j][k]表示前i辆车中派出j辆到A地,派出k辆到B地可以获得的最大利润
        int[][] dp = new int[a + 1][b + 1];
        for(int i = 1; i <= n; i++) {
            params = br.readLine().trim().split(" ");
            x = Integer.parseInt(params[0]);
            y = Integer.parseInt(params[1]);
            for(int j = Math.min(a, i); j >= Math.max(0, a - n + i); j--) {
                for(int k = Math.min(b, i - j); k >= Math.max(0, a + b - n + i - j); k--) {
                    if(j == 0 && k == 0) continue;
                    if(k == 0){
                        // B地的车够了,第i辆车不派出或者派到A地
                        dp[j][k] = Math.max(dp[j][k], dp[j - 1][k] + x);
                    }else if (j == 0){
                        // A地的车够了,第i辆车不派出或者派到B地
                        dp[j][k] = Math.max(dp[j][k], dp[j][k - 1] + y);
                    }else{
                        // 此时第i辆车可以选择往A地派也可以选择往B地派或不派
                        dp[j][k] = Math.max(dp[j][k], Math.max(dp[j - 1][k] + x, dp[j][k - 1] + y));
                    }
                }
            }
        }
        System.out.println(dp[a][b]);
    }
}


编辑于 2021-03-03 13:08:24 回复(8)
三维动态规划——优化用二维dp数组,可以参考以下网站的分析,看懂了~
发表于 2022-03-08 11:54:22 回复(0)

python 优化后还是被卡了时间。可以顺便看看 97. 交错字符串 - 力扣(LeetCode) ,这两道题很像。

n, a, b = list(map(int, input().split(" ")))
profit_a, profit_b = [0], [0]
for _ in range(n):
    x, y = list(map(int, input().split(" ")))
    profit_a.append(x), profit_b.append(y)
pre = [[0] * (b + 1) for _ in range(a + 1)]
cur = [[0] * (b + 1) for _ in range(a + 1)]
for i in range(1, n + 1):
    for j in range(a + 1):
        for k in range(b + 1):
            if j + k > i:
                break
            if j == 0 and k == 0:
                continue
            if k == 0:
                cur[j][k] = max(pre[j][k], pre[j - 1][k] + profit_a[i])
            elif j == 0:
                cur[j][k] = max(pre[j][k], pre[j][k - 1] + profit_b[i])
            else:
                p_a = pre[j - 1][k] + profit_a[i]
                p_b = pre[j][k - 1] + profit_b[i]
                cur[j][k] = max(pre[j][k], p_a, p_b)
    pre, cur = cur, pre
print(pre[a][b])
编辑于 2022-03-14 23:14:01 回复(0)
#include "bits/stdc++.h"
using namespace std;

int main() {
    std::ios::sync_with_stdio(false);
    std::cin.tie(nullptr);

    int n, a, b; std::cin >> n >> a >> b;
    // 选a个first, b个second -> max profit
    // 前i辆车,j个first,k个second
    std::vector<std::vector<std::vector<int>>> dp(2, std::vector<std::vector<int>>(a + 1, std::vector<int>(b + 1)));

    for (int i = 1;i <= n; i++) {
        int now = i & 1, pre = now ^ 1;
        int x, y; std::cin >> x >> y;
        for(int j = min(i, a);j >= max(0, a - (n - i)); j--) {
            for(int k = min(b, i - j);k >= max(0, a + b - n + i - j); k--) {
                dp[now][j][k] = dp[pre][j][k];
                if(j) dp[now][j][k] = max(dp[now][j][k], dp[pre][j - 1][k] + x);
                if(k) dp[now][j][k] = max(dp[now][j][k], dp[pre][j][k - 1] + y);
            }
        }        
    }

    std::cout << dp[n & 1][a][b] << std::endl;
}

发表于 2022-02-11 23:03:40 回复(0)