zoukankan      html  css  js  c++  java
  • 递归改动态规划

    递归是一种尝试,比如我不知道一个问题的解决方法,但是我知道怎么去尝试。

    左神说图灵就是将计算机用于尝试,在此之前,都是知道解决问题的固定方法,然后用计算机来解决。因此被誉为计算机之父。

    其实最早使用计算机的是拜伦的女儿。第一位计算机程序员是女性哦。

     

    P问题:是否可以在多项式时间内求出问题的解

    NP问题:可以在多项式的时间里验证(猜出)一个解的问题。

    NPC(NP-完全问题):1、是一个NP问题   2、所有的NP问题都可以约化到它

    约化(Reducibility,归约):一个问题A可以约化为问题B的含义即是,可以用问题B的解法解决问题A,或者说,问题A可以“变成”问题B。“问题A可约化为问题B”有一个重要的直观意义:B的时间复杂度高于或者等于A的时间复杂度。而且,约化具有传递性。

     NP-Hard问题:满足NPC问题定义的第二条但不一定要满足第一条,所有的NP问题都可以约化到它,但是他不一定是NP问题。

    题目1:给定二维数组,从左上角到右下角,每一步只能向下或者向右,沿途经过的数累加,返回最小路径和

    package day6;
    /*
     *     给定二维数组,从左上角到右下角,每一步只能向下或者向右,
     *     沿途经过的数累加,返回最小路径和
     * 
     *     从(0,0)------>(n,n)
     */
    public class Code06_PathMinSum {
        //递归(会重复计算)
        public static int getMin1(int arr[][],int i, int j, int sum) {
            if (i== arr.length -1 && j == arr[0].length -1) {
                sum= arr[i][j];
            }
            else if (i == arr.length -1) {
                sum=  arr[i][j]+getMin1(arr,i,j+1,sum);
            }
            else if (j == arr[0].length -1) {
                sum=  arr[i][j]+getMin1(arr,i+1,j,sum);
            }
            else {    
                sum=  arr[i][j] +Math.min(getMin1(arr,i+1,j,sum), getMin1(arr,i,j+1,sum));
            }
            return sum;
        }
        //动态规划
        public static int getMin2(int arr[][]) {
            //考虑不存在的情况啊
            if(arr == null || arr.length ==0 || arr[0] == null || arr[0].length == 0) {
                return 0;
            }
            int n = arr.length -1;
            int m = arr[0].length -1;
            int  srr[][] = new int [n+1][m+1];
            for (int i = n ;i >=0 ;i--){
                for(int j = m ;j>=0 ;j--){
                    if (i == n && j == m) {
                        srr[n][m] = arr[n][m];
                    }
                    else if(i == n) {
                        srr[i][j]=arr[i][j] + srr[i][j+1];
                    }
                    else if (j == m) {
                        srr[i][j]= arr[i][j] + srr[i+1][j];
                        
                    }else {
                        srr[i][j] =arr[i][j]+ Math.min(srr[i+1][j],srr[i][j+1] );
                        
                    }
                }    
            }
            return srr[0][0];
        }
        
        
        
        // for test
        public static int[][] generateRandomMatrix(int rowSize, int colSize) {
            if (rowSize < 0 || colSize < 0) {
                return null;
            }
            int[][] result = new int[rowSize][colSize];
            for (int i = 0; i != result.length; i++) {
                for (int j = 0; j != result[0].length; j++) {
                    result[i][j] = (int) (Math.random() * 10);
                }
            }
            return result;
        }
        
        
        //test
        public static void main(String[] args) {
            int arr[][] = {
                    {3,2,1,0,},
                    {7,5,0,1,},
                    {3,7,6,2,},
            };
            
            System.out.println(getMin1(arr,0,0,0));
            System.out.println(getMin2(arr));
            
            
            arr = generateRandomMatrix(6, 7);
            System.out.println(getMin1(arr,0,0,0));
            System.out.println(getMin2(arr));
            
            
        }
    
    }

    题目2:给定一个数组arr[],和一个数aim,从数组中任意选数,问是否可以能累加得到aim,能返回true,不能返回false

    package day6;
    /*
     *     给定一个数组arr,和一个数aim
     *     从数组中任意选数,问是否可以能累加得到aim,
     *     能返回true,不能返回false
     */
    public class Code07_CanGetAim {
        
        public static boolean canGetAim(int arr[],int aim) {
            return  fun1(arr, 0,aim,0);
            
        }    
        //递归
        public static boolean fun1(int arr[] , int n ,int aim,int sum) {
            if (sum == aim) {
                return true;
            }
            if(n == arr.length) {
                return false;
            }
            return fun1(arr ,n+1,aim,sum+arr[n]) || fun1(arr ,n+1,aim,sum) ;
        }
        
        
        //动态规划
        
        public static boolean fun2(int arr[],int aim) {
            if (arr == null) return false;
            //预处理,数组中可能有正数,也可能有负数
            //sum 的范围 minn ~ maxx  共 maxx -minn +1个数 
            //对应下标(偏移) 坐标+min
            int maxx = 0, minn = 0;
            for (int i = 0 ; i < arr.length ;i ++) {
                if (arr[i] >0) {
                    maxx += arr[i];
                }else {
                    minn+= arr[i];
                }
            }
            if (aim >maxx || aim < minn) return false;    //保证aim在区间里
            
            int num =arr.length;
            int sum = maxx-minn;
            boolean dp[][] = new boolean [num+1][sum+1];
            //System.out.println(minn +" " +maxx);
            
            //一个是赋值一列,一个是赋值一个 ,效果一样
            //aim 是数,数变下标是 -min
            
            //dp[num][aim-minn] = true;
            for (int i = num; i>0;i--) {
                dp[i][aim-minn] = true;
            }
            
    
            
            for (int i = num-1 ; i>=0 ;i--) {
                for (int j =0; j<sum ;j++) {
                    //j是下标,j表示的数 j+minn,下标变数+min            
                    if (j+arr[i] > sum || j+arr[i] < 0) {
                        dp[i][j]= dp[i+1][j]; 
                    }else {
                        dp[i][j]= (dp[i+1][j] || dp[i+1][j+arr[i]]);
                    }
                        
                }
            }
            
            return dp[0][0];
            
        }
        
        // for test
        public static int[] generateRandomMatrix(int maxSize, int maxValue) {
            if (maxSize < 0 ) {
                return null;
            }
            int[] result = new int[maxSize];
            for (int i = 0; i != result.length; i++) {
                    result[i] = (int) (Math.random() * maxValue);
            }
            return result;
        }
    
        public static void  printArrays(int arr[]) {
            for (int i = 0 ; i< arr.length ; i++) {
                System.out.print(arr[i]+" ");
            }
            System.out.println();
        }
        
        public static void main(String[] args) {
    //        int arr[]= {3,2,7,13};//{3,2,1,-1};
    //        int aim = 4;//9;
    //        System.out.println(canGetAim(arr, aim));
    //        System.out.println(fun2(arr, aim));
            int n =100,maxSize = 20,maxValue = 8,aim =44;
            boolean flag = true;
            for (int i = 0 ; i <n ; i ++) {
                int arr[] = generateRandomMatrix(maxSize, maxValue);
                if(fun2(arr, aim) != canGetAim(arr, aim)) {
                    flag = false;
                    printArrays(arr);
                    System.out.println(canGetAim(arr, aim));
                    System.out.println(fun2(arr, aim));
                    break;
                }
            }
            System.out.println(flag ? "Nice!":"WOw!!!!Problem show up !!!!!!!"); 
            
        }
    }

    可以将动态规划中return dp[0][0]前的for循环替换成下面,效果相同,更简洁。核心代码就这一点。可对比递归。

            //这样写更加简洁,道理相同
            for (int i = num-1 ; i>=0 ;i--) {
                for (int j =sum; j>=0 ;j--) {//注意这里的j必须从后往前
                    //j是下标,j表示的数 j+minn,下标变数+min                
                    dp[i][j]= dp[i+1][j]; 
                    if (j+arr[i] <=sum &&  j+arr[i] >= 0) {
                        dp[i][j]= (dp[i][j] || dp[i+1][j+arr[i]]);
                    }                
                }
            }

     总结——递归改动态规划:

    一、条件

      1,有重复的状态

      2,无后效应问题。即状态与路径无关(到达这个状态之后,无论怎么到达这个状态的,往后走的路与前面无关。类似于入此门,前尘往事尽斩断),进一步讲,可变参数确定之后,返回值就确定了。

    二、方法(套路)

      1,按照要求写出递归版本

      2,找到需要求解的位置

      3,回到basecase中,将不被依赖的位置设置好(如题2就是最后一行)

      4,回到一般位置(情况),找到依赖关系。

  • 相关阅读:
    inspector元素定位[wda-facebook]
    pip下载 requirements.txt
    APP运行出现闪退
    安卓的webview报错
    深度强化学习入门笔记
    强化学习入门笔记
    如何将本地代码上传到GitHub
    Sublime插件Emmet的错误及Tab补全代码
    flask的url错误
    计算输出特征图的空间尺寸
  • 原文地址:https://www.cnblogs.com/codinghard/p/11510828.html
Copyright © 2011-2022 走看看