动态规划经典例题java实现

    动态规划算法通常基于一个递推公式及一个或多个初始状态。当前子问题的解将由上一次子问题的解推出。使用动态规划来解题只需要多项式时间复杂度,因此它比回溯法、暴力法等要快许多。
    解决动态规划问题的关键是要找到状态转移方程。将问题分解成最小的子问题,找到由子问题到全局问题的解决方案。

    可以采用动态规划求解的问题的一般要具有3个性质:
    (1) 最优化原理:如果问题的最优解所包含的子问题的解也是最优的,就称该问题具有最优子结构,即满足最优化原理。
    (2) 无后效性:即某阶段状态一旦确定,就不受这个状态以后决策的影响。也就是说,某状态以后的过程不会影响以前的状态,只与当前状态有关。
   (3)有重叠子问题:即子问题之间是不独立的,一个子问题在下一阶段决策中可能被多次使用到。(该性质并不是动态规划适用的必要条件,但是如果没有这条性质,动态规划算法同其他算法相比就不具备优势)。

    求解动态规划问题的基本步骤:
    (1)分析最优解的性质,并刻画其结构特征。
    (2)递归的定义最优解。
    (3)以自底向上或自顶向下的记忆化方式(备忘录法)计算出最优值
    (4)根据计算最优值时得到的信息,构造问题的最优解

例1:有n级台阶,一个人每次上一级或者两级,问有多少种走完n级台阶的方法。

在这个问题上,我们让f(n)表示走上n级台阶的方法数。那么当n为1时,f(n) = 1,n为2时,f(n) =2,就是说当台阶只有一级的时候,方法数是一种,台阶有两级的时候,方法数为2。那么当我们要走上n级台阶,必然是从n-1级台阶迈一步或者是从n-2级台阶迈两步,所以到达n级台阶的方法数必然是到达n-1级台阶的方法数加上到达n-2级台阶的方法数之和。即f(n) = f(n-1)+f(n-2),我们用dp[n]来表示动态规划表,dp[i],i>0,i<=n,表示到达i级台阶的方法数。

public class steps {
static int[] array;
public static int step(int n){
if(n<=2)  
           return n;  
       int f = 1%2147483647;  
       int s = 2%2147483647;  
       int t = 0;  
       for(int i=3;i<=n;i++){  
        t = (f+s)%2147483647;  
        f = s;  
        s = t;  
       }  
      return t;   
}
public static void main(String[] args) {
System.out.println(step(5));
}
}

例2:有一个矩阵map,它每个格子有一个权值。从左上角的格子开始每次只能向右或者向下走,最后到达右下角的位置,

 路径上所有的数字累加起来就是路径和,返回所有的路径中最小的路径和。

我们必须注意到的一点是,到达一个格子的方式最多只有两种:从左边来的(除了第一列)和从上边来的(除了第一行)。因此为了求出到达当前格子的最短路径,我们就要先去考察那些能到达当前这个格子的格子,到达它们的最短路径。经过上面的分析,很容易可以得出问题的状态和状态转移方程。状态S[i][j]表示我们走到(i, j)这个格子时,最短的路径。那么,状态转移方程如下:
S[i][j]=A[i][j] + min(S[i-1][j], if i>0 ; S[i][j-1], if j>0)
其中i代表行,j代表列,下标均从0开始。

public class MinPath {
	public static int getMin(int[][] map, int n, int m) {   
       int[][] dp = new int[n][m];  
        for(int i=0;i<n;i++){        //初始化第一列的值
            for(int j=0;j<=i;j++){  
             dp[i][0]+=map[j][0];      
            }  
        }  
        for(int i=0;i<m;i++){       //初始化第一行的值
            for(int j=0;j<=i;j++){  
             dp[0][i]+=map[0][j];      
            }  
        }  
        for(int i=1;i<n;i++){  
            for(int j=1;j<m;j++){  
             dp[i][j] = min(dp[i][j-1]+map[i][j],dp[i-1][j]+map[i][j]);     
            }  
        }  
        return dp[n-1][m-1];  
    }  
    public static int min(int a,int b){  
        if(a>b){  
         return b;     
        }else{  
         return a;     
        }  
    }  
	public static void main(String[] args) {
	    Scanner sc=new Scanner(System.in);
	    int m=sc.nextInt();
	    int n=sc.nextInt();
	    int map[][]=new int[m][n];
	    for(int i=0;i<m;i++){
	    	for(int j=0;j<n;j++){
	    		map[i][j]=sc.nextInt();
	    	}
	    }	    System.out.println(getMin(map,m,n));
	}

例3:给定两个字符串A和B,返回两个字符串的最长公共子序列的长度。

设dp[n][m] ,为A的前n个字符与B的前m个字符的公共序列长度,则当A[n]==B[m]的时候,dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]),否则,dp[i][j] =max(dp[i-1][j],dp[i][j-1]);

public class LCS {
	public static int findLCS(String A, int n, String B, int m) {  
        int[][] dp = new int[n][m];  
        char[] a = A.toCharArray();  
        char[] b = B.toCharArray();  
       for(int i=0;i<n;i++){  
           if(a[i]==b[0]){  
               dp[i][0] = 1;  
               for(int j=i+1;j<n;j++){  
                   dp[j][0] = 1;  
               }  
               break;  
           }             
       }  
         for(int i=0;i<m;i++){  
           if(a[0]==b[i]){  
               dp[0][i] = 1;  
               for(int j=i+1;j<m;j++){  
                   dp[0][j] = 1;  
               }  
               break;  
           }              
       }  
       for(int i=1;i<n;i++){  
           for(int j=1;j<m;j++){  
               if(a[i]==b[j]){  
                  dp[i][j] = max(dp[i-1][j-1]+1,dp[i-1][j],dp[i][j-1]);  
               }else{  
                   dp[i][j] = Math.max(dp[i-1][j],dp[i][j-1]);  
               }                    
           }  
       }           
        return dp[n-1][m-1];  
    }  
    public static int max(int a,int b,int c){  
        int max = a;  
        if(b>max)  
            max=b;  
        if(c>max)  
            max = c;  
        return max;  
    }  
	public static void main(String[] args) {		    System.out.println(findLCS("1A3C3D4B56",10,"B1D23CA45B6A",12));
	}
}

点赞