携程笔试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];
    }
原文地址:https://www.cnblogs.com/wsZzz1997/p/14766493.html