动态规划经典例题

动态规划

关键在于填表以及输出过程(个人理解)

算法思想

把原问题分解成若干个简单的子问题,保存已解决的子问题答案,避免重复计算。动态规划常应用于有重叠子问题和最优子结构性质的问题。
子问题最优从而达到全局最优。

算法基本步骤

  1. 找出最优解的性质
  2. 递归的定义最优值
  3. 以自底向上的方式计算最优值
  4. 根据计算最优值的信息构造最优解


经典案例一 0/1背包问题

背包问题

import java.util.Scanner;
import static sun.misc.Version.println;

public class Dp{
    int n,v;//物品数量和容积
    int value[];
    int weight[];
    int dp[][];//dp[i][j]表示i个物品,容积为j时得到的最大价值
    public void Maxvalue(){
        for(int i=1;i<=n;i++){
            for(int j=0;j<=v;j++){//注意下标还有别的写法
               if(j>=weight[i]){
            dp[i][j]=Math.max(value[i]+dp[i-1][j-weight[i]], //拿了第i个
                    dp[i-1][j]);//没拿
        }
            else{
                dp[i][j]=dp[i-1][j];
            }}       
        }
        for(int i=0;i<=n;i++){
           for(int j=0;j<=v;j++){
                System.out.print(dp[i][j] + " ");
                }
           System.out.println();
        }
        }      
    public void BestResult(int n,int v){
            boolean isAdd[]=new boolean[n+1];//记录物品是否拿了
            for(int i=n;i>=1;i--){    // 倒序
                if(dp[i][v]==dp[i-1][v]){
                isAdd[i]=false;}
            else{
                    isAdd[i]=true;}
               v-=weight[i];
        }
            for(int i=1;i<=n;i++){//把结果正序输出
                System.out.println(i+"是"+isAdd[i]);
            }
    }
    public void Init(){
        Scanner sc =new Scanner (System.in);
        n=sc.nextInt();
        v=sc.nextInt();
        weight=new int [n+1];
        value=new int [n+1];
        dp=new int[n][v];
        for(int i=1;i<=n;i++){
            weight[i]=sc.nextInt();
        }
        for(int i=1;i<=n;i++){
            value[i]=sc.nextInt();
        }    
    }
    public  static void main(String[] args){
        Dp bag=new Dp();
        bag.Init();
        bag.Maxvalue();
        bag.BestResult(bag.n,bag.v);
        
    }
    
}

经典例题二 矩阵连乘问题

动态规划矩阵连乘

public class dp_matrix {
    int j=6;
    int p[];
    int s[][];//记录断点k
    int dp[][];//最小代价  
public dp_matrix() {
    p=new int[]{10,15,25,35,20,10,40};
    s=new int[j][j];
    dp=new int[j][j];
}   
 public void dp_matrix(){ 
     
         for(int i=0;i<j;i++){
           dp[i][i]=0;}
         for(int r=2;r<=j;r++){
         for(int i=0;i<=j-r;i++){
             int n=i+r-1;                        
           dp[i][n]=dp[i+1][n]+p[i]*p[i+1]*p[n+1];//i<j
                   s[i][n]=i;//在i+1分的
                   for(int k=i+1;k<n;k++){
                       int key=dp[i][k]+dp[k+1][n]+p[i]*p[k+1]*p[n];//注意下标
                       if(key<dp[i][n]){
                           dp[i][n]=key;//更新
                           s[i][n]=k;// 更新        
                   }
                   }}        
                          }}
                          
               public void traceBack(int i ,int j){
                   if(i==j){
                   System.out.print(i);}
                   else{
                   System.out.print("(");
    		traceBack(i,s[i][j]);
    		traceBack(s[i][j]+1,j);
                System.out.print(")");
    		}                                  
 }        
        public static void main(String[] args){
            dp_matrix matrix=new dp_matrix();
                 matrix.dp_matrix();
                   matrix.traceBack(0,5);   
        }
}

经典例题三 最长公共子序列

   public class Dp_Lcs {
   public void  Maxlength(){
       String []m={"a","b","c","d"};
       String []n={"b","c","d"};
       int x=m.length;
       int y=n.length;
      int [][] dp=new int[m.length+1][n.length+1];//dp[i][j]表示xi与yi两个序列最长公共子序列的长度
      int[][] s=new int[m.length][n.length];//s[i][j]用来储存m[i]与n[j]之间的关系
       for(int i=0;i<=x;i++){//初始化
           dp[i][0]=0;
       }
       for(int i=0;i<=y;i++){
           dp[0][i]=0;
       }
       for(int i=1;i<=x;i++){
           for(int j=1;j<=y;j++){
               if(m[i-1]==(n[j-1])){    //相等时  
                   dp[i][j]=dp[i-1][j-1]+1;//参照图
                   s[i-1][j-1]=1;
               }
               else {dp[i][j]=Math.max(dp[i-1][j], dp[i][j-1]);
               if(dp[i][j]==dp[i-1][j]){
                   s[i-1][j-1]=-1;
               }
               else s[i-1][j-1]=0;
               }
           }
   } 
       for(int i=0;i<x;i++){
           for(int j=0;j<y;j++){
               System.out.print(s[i][j]);}
             System.out.println();  
           }
          for(int i=0;i<x+1;i++){
           for(int j=0;j<y+1;j++){
               System.out.print(dp[i][j]);}
      System.out.println();

}
           System.out.println("最长为"+" ");
           LCS(s,m,x,y);        
}      
public  void LCS(int[][] s, String[] m, int i, int j){//{递归遍历s[i][j]
    if(i == 0 || j == 0){ return;}
    switch (s[i-1][j-1]) {
        case 1:
            LCS(s,m,i - 1, j - 1);
            System.out.println(m[i-1]+ " ");
            break;
        case 0:
            LCS(s,m,i - 2, j);
            break;
        default:
            LCS(s,m,i, j-2);
            break;
    }
  }
    public static void main(String[] args) {
        Dp_Lcs a=new Dp_Lcs();
                a.Maxlength();  
}
}
posted @ 2020-04-03 20:40  小白贼菜  阅读(890)  评论(0)    收藏  举报