• 携程笔试2-动态规划


    动态规划题:

    出租车选单:

    输入

    1 2 3 3 开始时间

    3 4 5 6 结束时间

    200 150 180 210 每单的金钱

    订单时间不能重合:例如,选了13  就不能选 24 ,但可以选3 5  或者 3 6

    回溯思路:订单排序,按startTime,endTime

    然后一次取出订单,选择接单或者不接单,(需要考虑,接单的startTime必须大于等于上一次接单的endTime)。

    共有2^n种情况。

    优化:可以加入的剪枝操作,当当前的startTime小于最后一次的endTime时,直接退出循环

    if(quest.startTime<endTime){
    maxMoney = Math.max(maxMoney,curMoney);
    return;
    }

    用的回溯:只通过了33%

    public class Xiecheng1 {
    
        public static void main(String[] args) {
            Scanner scanner = new Scanner(System.in);
    //        int n = Integer.valueOf(scanner.nextLine());
    //        String[] startTime = scanner.nextLine().split(" ");
    //        String[] endTime = scanner.nextLine().split(" ");
    //        String[] moneys = scanner.nextLine().split(" ");
            int n = 4;
            String[] startTime = "1 2 3 3".split(" ");
            String[] endTime = "3 4 5 6".split(" ");
            String[] moneys = "200 150 180 210".split(" ");
    
            System.out.println(maxValue(n, startTime, endTime, moneys));
        }
        public static int maxMoney=0;
    
        private static int maxValue(int n, String[] startTime, String[] endTime, String[] moneys) {
            PriorityQueue<Quest> list= new PriorityQueue<>(new Comparator<Object>() {
                @Override
                public int compare(Object o1, Object o2) {
                    Quest q1 = (Quest) o1;
                    Quest q2 = (Quest) o2;
                    if(q1.startTime!=q2.startTime){
                        return q1.startTime - q2.startTime;
                    }else{
                        return q1.endTime-q2.endTime;
                    }
    
                }
            });
    
            for (int i = 0; i < n; i++) {
                int a = Integer.parseInt(startTime[i]);
                int b = Integer.parseInt(endTime[i]);
                int c = Integer.parseInt(moneys[i]);
                list.add(new Quest(a,b,c));
            }
            Quest[] quests = new Quest[n];
            for (int i = 0; i < n; i++) {
                quests[i] = list.poll();
            }
    
            solution(0,n,0,0,quests);
    
            return maxMoney;
        }
    
        public static void solution(int c, int n, int endTime,int curMoney, Quest[] quests){
            if(c == n){
                maxMoney = Math.max(maxMoney,curMoney);
                return;
            }
            // 这次选
            Quest quest = quests[c];
            if(quest.startTime>=endTime){
                solution(c+1,n,quest.endTime,curMoney+quest.money,quests);
            }
            // 这次不选
            solution(c+1,n,endTime,curMoney,quests);
    
        }
    
    }
    class Quest{
        public Quest(int startTime,int endTime, int money){
            this.startTime = startTime;
            this.endTime = endTime;
            this.money = money;
        }
        public int startTime;
        public int endTime;
        public int money;
    }

    在复习了01背包以及完全背包问题后:对该问题进行了重新解答:

    /**
         * 共有n个单子:尽可能多的接单,使收益最大,时间不重叠
         * s:开始时间,e:结束时间,m:本单的收益
         *
         */
        @Test
        public void test2(){
            int n  = 6;
            int[] starts = {1,1,2,3,4,5};
            int[] ends = {2,3,4,5,6,6};
            int[] moneys = {50,100,150,200,180,90};
    
            System.out.println(maxMoney(n, starts, ends, moneys));
        }
    
        public int maxMoney(int n, int[] starts, int[] ends, int[] moneys){
            int maxLength = Arrays.stream(ends).max().getAsInt();
            // dp[i][j] 前i个订单中,不重合,选到endTime时间达到j时最大利润
            int[][] dp = new int[n][maxLength+1];
    
            // 初始化
            for(int i=0; i <= maxLength; i++){
                if(i==ends[0]){
                    dp[0][i] = moneys[0];
                }
    
            }
            for(int i=1; i<n; i++){
                for(int j=0; j<=maxLength; j++){
                    if(j==ends[i]) {
                    // 当前任务选了之后达到j 以及 当前任务没选,之前选了达到的j
    
                    // 如果选当前任务,那么就从starts之前的最大值与当前money结合
                    // temp表示:上一层中在starts[i]之前结束的最大money
                        int temp = 0;
                        for (int k = 0; k <= starts[i]; k++) {
                            temp = Math.max(dp[i - 1][k], temp);
                        }
                        // 如果不选当前任务
                        dp[i][j] = Math.max(temp + moneys[i], dp[i - 1][j]);
                    }else if(j<ends[i]) {
                        // 本次没有选择当时到了j
                        dp[i][j] = dp[i - 1][j];
                    }
                    if(j>ends[i]){
                        break;
                    }
                }
            }
            int ret=0;
            for(int i=0; i<=maxLength; i++){
                ret = Math.max(ret,dp[n-1][i]);
            }
    
            for (int[] ints : dp) {
                for (int anInt : ints) {
                    System.out.print(anInt+" ");
                }
                System.out.println();
            }
    
            return dp[n-1][maxLength];
        }
  • 相关阅读:
    第六周作业
    第二次作业
    自我介绍
    2019春总结作业
    2019春第四次课程设计实验报告
    2019春第三次课程设计实验报告
    2019春第二次课程设计实验报告
    2019春第一次课程设计实验报告
    第十二周编程总结
    第十一周编程总结
  • 原文地址:https://www.cnblogs.com/wsZzz1997/p/14766493.html
Copyright © 2020-2023  润新知