5.13某互联网厂笔试题复现

第一题

题目大意:

给出一组有序的旅游景点,到达该景点会获取不同的分数作为奖励。参加比赛的选手都从第一站开始,自动会获取该景点的分数。每位参赛者会有一组数值一样的卡片,每张卡片上有一个数字1,2,3或者4,不同的数字代表前进的步数。如何使用卡片前进,会使得获得的分数最大。

输入:scores数组代表当前给出的各个景点的分数
cards数组代表当前给出的卡片
求获得的最高的分数

思路:

线性DP求解
首先统计出每个卡片数字的个数,保存在一个一维数组中
然后创建一个四维的dp数组,数组的索引就是每个卡片数字的个数.
相当于对四种卡片进行组合,每种数字最多有40个,每一次都选择前一次的最优的走法,所以最后一定是全局最优的.

代码:

import java.util.*;

public class Main1{
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = sc.nextInt();
        int[] scores = new int[n];
        for(int i=0;i<n;i++){
            scores[i]=sc.nextInt();
        }
        int m = sc.nextInt();
        int[] cards = new int[m];
        for(int i=0;i<m;i++){
            cards[i] = sc.nextInt();
        }
        System.out.println(solution(scores, cards));
    }

    public static int solution(int[] scores, int[] cards){
        int[] num = new int[5];
        int[][][][] dp = new int[41][41][41][41];
        for(int i=0;i<cards.length;i++){
            num[cards[i]]++;
        }
        dp[0][0][0][0] = scores[0];
        for(int i=0;i<=num[1];i++){
            for(int j=0;j<=num[2];j++){
                for(int m=0;m<=num[3];m++){
                    for(int n=0;n<=num[4];n++){
                        int pos = i+j*2+m*3+n*4;
                        if(i!=0){
                            dp[i][j][m][n] = Math.max(dp[i][j][m][n],
                                    dp[i-1][j][m][n]+scores[pos]);
                        }
                        if(j!=0){
                            dp[i][j][m][n] = Math.max(dp[i][j][m][n],
                                    dp[i][j-1][m][n]+scores[pos]);
                        }
                        if(m!=0){
                            dp[i][j][m][n] = Math.max(dp[i][j][m][n],
                                    dp[i][j][m-1][n]+scores[pos]);
                        }
                        if(n!=0){
                            dp[i][j][m][n] = Math.max(dp[i][j][m][n],
                                    dp[i][j][m][n-1]+scores[pos]);
                        }
                    }
                }
            }
        }
        return dp[num[1]][num[2]][num[3]][num[4]];
    }
}

第二题

题目大意:

租车店只剩下一辆车可以租,但是一天内有n个订单,每个订单的用车开始时间为第X小时,用车结束时间为Y小时,订单金额为Z,计算怎样安排订单可以获得的最大收益

输入:整数n(1<=n<=10),表示n个订单
读入用空格分隔的整数,表示订单的开始时间
读入用空格分隔的整数,表示订单的结束时间
读入用空格分隔的整数,表示订单金额
4
1 2 3 3
3 4 5 6
200 150 180 210
输出 410

思路:

还是考虑动态规划做,回溯应该也可以,可能会超时.这题是最大收益问题.
首先考虑当前时间段的订单选择还是不选择,如果不选择那么收益为前一个时间段获得的最大收益,如果选择,就必须找到符合当前时间段的前一个时间段的订单最大收益,再加上当前时间段的收益.
状态转移方程: dp[i] = Math.max(dp[i-1], dp[pre[i]]+value)
所以需要维护一个pre数组,存储当前时间段的前一个可以完成的订单所在的索引.如果前面没有符合的订单就置为-1.

这一题当时没有提交成功,此代码为之后完成的,如果代码有问题,不能通过用例,希望大家可以提出来,虚心接受大家的指导和建议,继续将代码完善.

代码:

import java.util.*;

public class Main1{

    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int n = Integer.parseInt(sc.nextLine());
        String[] start = sc.nextLine().trim().split(" ");
        String[] end = sc.nextLine().trim().split(" ");
        String[] value = sc.nextLine().trim().split(" ");
        int[][] data = new int[n][3];
        for(int i=0;i<n;i++){
            data[i][0] = Integer.parseInt(start[i]);
            data[i][1] = Integer.parseInt(end[i]);
            data[i][2] = Integer.parseInt(value[i]);
        }

        System.out.println(solution(data));
    }

    public static int solution(int[][] data) {
   		//维护一个与当前时间段不冲突的最近一次时间段的索引
        int[] pre = new int[data.length];
        //先全部填充-1,没有满足的索引就保持-1
        Arrays.fill(pre, -1);
        for(int i=1;i<data.length;i++){
            for(int j=i-1;j>=0;j--){
                if(data[j][1]<=data[i][0]){
                //找到与当前时间段最近的复合的索引,并记录
                    pre[i]=j;
                    break;
                }
            }
        }
        int[] dp = new int[data.length];
        dp[0]=data[0][2];
        for(int i=1;i<data.length;i++){
            if(pre[i]!=-1){
                dp[i] = Math.max(dp[i-1],dp[pre[i]]+data[i][2]);
            }else if(pre[i]==-1){
                dp[i] = Math.max(dp[i-1],data[i][2]);
            }
        }
        return dp[data.length-1];
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值