奇妙的算法【7】-贪婪算法-dp

问题1描述:【贪婪算法,Dijistra算法】

①有一只兔子要从一个N*N的二维矩阵方格中从上跳到下面;

②每次只能向左或向下,越过一个方格,跳到下一个方格中;

③被越过的方格中的数值,表示该兔子越过该方格后需要休息的时间(或者能量);

求:到达最下面方格花费的最少时间是多少?

输入:

第一行,输入一个数值N

后面输入N行,每行有N个数值并且由【,】隔开

输出:

输出一个数据M,M为兔子需要花费的最小时间

示例:
输入:
6
1,2,3,5,7,6
2,1,4,5,7,4
3,4,5,6,3,6
2,3,1,4,6,8
5,6,1,4,6,2
4,2,4,1,1,6
输出:
6
View Code

   

 

算法1【递归调用】:以后不考虑这种算法

注意:这种方法虽然可以结题,但是如果数据量太大,时间上耗时太多了,每次都不能全部AC,这次只能AC40%

package com.cnblogs.mufasa.demo1;

import java.util.Scanner;

class Answer1_1 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        String line = scanner.nextLine();
        int n = Integer.parseInt(line);
        int[][] area = new int[n][n];

        for (int i = 0; i < n; i++) {
            line = scanner.nextLine();
            String[] split = line.split(",");
            if (split.length != n) {
                throw new IllegalArgumentException("错误输入");
            }
            int j = 0;
            for (String num : split) {
                area[i][j++] = Integer.parseInt(num);
            }
        }

        int minimumTimeCost = getMinimumTimeCost(n,area);
        System.out.println(minimumTimeCost);
    }

    /** 请完成下面这个函数,实现题目要求的功能 **/
    /** 当然,你也可以不按照这个模板来作答,完全按照自己的想法来 ^-^  **/
    private static int getMinimumTimeCost(int n, int[][] area) {
        long startTime =  System.currentTimeMillis();
        int[] nums=new int[n];
        for(int i=0;i<n;i++){
            nums[i]=getMinSingleLine(n,area,0,i,0);
        }
        int min=nums[0];
        for(int i=1;i<n;i++){
            if(min>nums[i]){
                min=nums[i];
            }
        }
        long endTime =  System.currentTimeMillis();
        System.out.println(endTime-startTime);
        return min;
    }

    private static int getMinSingleLine(int n,int[][] area,int index0,int index1,int times ){
        if(index0==n-2&&(index1==n-1||index1==n-2)){//1,极限位置,正确
            return times+area[index0+1][index1];
        }else if(index1==n-1||index1==n-2){//2,只能往下走,正确
            return getMinSingleLine(n,area,index0+2,index1,times+area[index0+1][index1]);
        }else if(index0==n-2){//3,向下一步或向右,正确
            return Math.min(times+area[index0+1][index1],getMinSingleLine(n,area,index0,index1+2,times+area[index0][index1+1]));
        }else{
            return Math.min(getMinSingleLine(n,area,index0+2,index1,times+area[index0+1][index1]),getMinSingleLine(n,area,index0,index1+2,times+area[index0][index1+1]));
        }
    }
}
/*
8
35,92,98,68,35,65,26,72
29,78,83,16,5,89,92,28
48,51,37,79,65,74,50,71
98,78,99,57,1,30,22,16
72,88,55,33,56,58,28,49
4,28,29,20,18,61,11,73
61,19,47,34,85,32,77,89
29,49,10,81,52,5,63,25
 */
View Code

 

算法2【贪婪算法】:Dijistra算法

算法思路:它和算法1中的原理有点像,但是引入了一个优先队列,每次进行移动都是从耗时最小的那个位置开始移动并且更新队列,当出现第一个到达目的地的数据 时,这个数据就是最快的数据

package com.cnblogs.mufasa.demo1;

import java.util.PriorityQueue;
import java.util.Scanner;

public class Answer1_2 {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);

        String line = scanner.nextLine();
        int n = Integer.parseInt(line);
        int[][] area = new int[n][n];

        for (int i = 0; i < n; i++) {
            line = scanner.nextLine();
            String[] split = line.split(",");
            if (split.length != n) {
                throw new IllegalArgumentException("错误输入");
            }
            int j = 0;
            for (String num : split) {
                area[i][j++] = Integer.parseInt(num);
            }
        }

        int minimumTimeCost = getMinimumTimeCost(n,area);
        System.out.println(minimumTimeCost);
    }
    /** 请完成下面这个函数,实现题目要求的功能 **/
    /** 当然,你也可以不按照这个模板来作答,完全按照自己的想法来 ^-^  **/
    private static int getMinimumTimeCost(int n, int[][] area) {//贪婪算法,每次对优先队列的最小对象进行操作
        long startTime =  System.currentTimeMillis();
        PriorityQueue<Loc> queue=new PriorityQueue<>(3*n);//最小堆实现优先队列
        for(int i=0;i<n;i++){//初始化触发机关的位置
            queue.add(new Loc(1,i,area[1][i]));
        }
        Loc preLoc;
        while (true){
            preLoc=queue.poll();
            if(preLoc.index0==n-1){//已经到达目的地
                break;
            }
            if(preLoc.index1==n-2||preLoc.index1==n-1){//右边界情况,只能向下
                queue.add(new Loc(preLoc.index0+2,preLoc.index1,preLoc.times+area[preLoc.index0+2][preLoc.index1]));
            }else {//可以向下、向右
                queue.add(new Loc(preLoc.index0+2,preLoc.index1,preLoc.times+area[preLoc.index0+2][preLoc.index1]));
                queue.add(new Loc(preLoc.index0,preLoc.index1+2,preLoc.times+area[preLoc.index0][preLoc.index1+2]));
            }
        }
        long endTime =  System.currentTimeMillis();
        System.out.println(endTime-startTime);
        return preLoc.times;
    }
    static class Loc implements Comparable{
        public int times;
        public int index0,index1;
        public Loc(int index0,int index1,int times){
            this.index0=index0;
            this.index1=index1;
            this.times=times;
        }
        @Override
        public int compareTo(Object obj) {
            return times-((Loc)obj).times;
        }
    }
}

/*
8
35,92,98,68,35,65,26,72
29,78,83,16,5,89,92,28
48,51,37,79,65,74,50,71
98,78,99,57,1,30,22,16
72,88,55,33,56,58,28,49
4,28,29,20,18,61,11,73
61,19,47,34,85,32,77,89
29,49,10,81,52,5,63,25
 */

 

问题2描述:

①若干男女生围成一圈;

②求身边女生个数最多的男生位置,个数相同去最先出现的同学;

③求男生最大的团体人数,其中最多可以包含k个女士;

 

举一反三

问题描述:

现有一个长度为n的序列,需要你求出最长的非增子序列,使得其长度最长,并且这个子序列是满足非增性质的。输出最长长度

输入样例:

5

1 2 1 3 4

输出样例:

4

其中有如下满足要求的子序列:

① 1 2 3 4;②1 1 3 4

posted on 2019-08-30 21:03  周健康  阅读(351)  评论(0编辑  收藏  举报

导航