《趣学算法》第四章 动态规划代码实现(Java)

本文深入探讨动态规划,通过Java代码详细解释了最长公共子序列、编辑距离、游艇租赁、矩阵连乘及0-1背包问题的解决方法,展示了动态规划在算法中的应用。
摘要由CSDN通过智能技术生成

4.3 最长的公共子序列

import java.util.Scanner;

public class Test4_3 {
    static String s1;
    static String s2;

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("输入字符串s1:");
        s1=scanner.next();
        System.out.println("输入字符串s2:");
        s2=scanner.next();
        int len1=s1.length();                          //计算两个字符串的长度
        int len2=s2.length();     

        int[][] c=new int[len1+1][len2+1];             //存放公共子序列的最大长度
        int[][] b=new int[len1+1][len2+1];             //记录来源

        for(int i=0;i<=len1;i++)
            c[i][0]=0;                                 //初始化第一列为0
        for(int j=0;j<=len2;j++)
            c[0][j]=0;                                 //初始化第一行为0

        LCSL(c,b);                                     //求解最长公共子序列
        System.out.println("s1和s2的最长公共子序列长度是:"+c[len1][len2]);
        System.out.print("s1和s2的最长公共子序列是:");
        print(len1,len2,b);                            //递归构造最长公共子序列最优解
    }

    /*求解最长公共子序列*/
    public static void LCSL(int[][] c,int[][] b) {
        int i,j;
        for(i=1;i<=c.length-1;i++) {                   //控制s1的序列,即遍历s1的每个字符
            for(j=1;j<=c[i].length-1;j++) {            //控制s2的序列,即用s1的字符与s2的所有字符进行比较

                if(s1.charAt(i-1)==s2.charAt(j-1)) {   //字符下标从0开始
                    //如果当前字符相同,则公共子序列的长度为该字符前的最长公共序列+1
                    c[i][j]=c[i-1][j-1]+1;
                    b[i][j]=1;
                }
                else {
                    if(c[i][j-1]>=c[i-1][j]) {         //找出两者最大值,若相等默认取左侧
                        c[i][j]=c[i][j-1];             //取左侧值
                        b[i][j]=2;
                    }
                    else {
                        c[i][j]=c[i-1][j];             //取上面值
                        b[i][j]=3;
                    }
                }
            }
        }
    }

    /*递归构造最长公共子序列最优解*/
    public static void print(int i,int j,int[][] b) {
        if(i==0||j==0)
            return;                                    //递归结束条件
        if(b[i][j]==1) {                               //来源左上角
            print(i-1,j-1,b);
            System.out.print(s1.charAt(i-1));
        }
        else if(b[i][j]==2) 
            print(i,j-1,b);                            //来源左侧
        else
            print(i-1,j,b);                            //来源上面               
    }
}

程序运行结果如下:
这里写图片描述

4.4 编辑距离

import java.util.Scanner;

public class Test4_4 {

    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("输入字符串str1:");
        String str1=scanner.next();
        System.out.println("输入字符串str2:");
        String str2=scanner.next();
        int answer=editDistance(str1,str2);                  //求编辑距离
        System.out.println(str1+"和"+str2+"的编辑距离是:"+answer);
    }

    public static int editDistance(String str1,String str2) {
        int len1=str1.length();                              //计算字符串的长度
        int len2=str2.length();
        int[][] d=new int[len1+1][len2+1];                   //d[i][j]表示str1前i个字符和str2前j个字符的编辑距离

        for(int i=0;i<=len1;i++)                             //当第二个字符串长度为0时,编辑距离初始化为i
            d[i][0]=i;
        for(int j=0;j<=len2;j++)                             //当第一个字符串长度为0时,编辑距离初始化为j
            d[0][j]=j;

        for(int i=1;i<d.length;i++) {                        //遍历str1的每个字符
            for(int j=1;j<d[i].length;j++) {                 //与第二个字符串的每个字符进行比较
                int diff;                                    //判断str1[i]是否等于str2[j],相等为0
                if(str1.charAt(i-1)==str2.charAt(j-1)) {     //字符串小标从0开始
                    diff=0;
                }
                else
                    diff=1;

                int temp=Math.min(d[i-1][j]+1, d[i][j-1]+1);  //去三者中最小值
                d[i][j]=Math.min(temp,d[i-1][j-1]+diff);
            }
        }
        return d[len1][len2];
    }

}

程序运行结果如下:
这里写图片描述

4.5 游艇租赁

import java.util.Scanner;

public class Test4_5 {
    static int n;
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入站点的个数n:");
        n=scanner.nextInt();
        System.out.println("请依次输入各站点之间的租金:");
        int[][] r=new int[n+1][n+1];                            //存放各站点之间的租金
        int[][] m=new int[n+1][n+1];                            //各个子问题的最优值
        int[][] s=new int[n+1][n+1];                            //各个子问题的最优决策
        for(int i=1;i<=n;i++) {
            for(int j=i+1;j<=n;j++) {
                r[i][j]=scanner.nextInt();
                m[i][j]=r[i][j];                                //初始化m数组
            }   
        }
        rent(m,s);                                              //求最少租金
        System.out.println("花费最少的租金为:"+m[1][n]);
        System.out.print("最少租金经过的站点:1");
        print(1,n,s);
        System.out.println();
        scanner.close();
    }

    /*最少租金求解函数*/
    public static void rent(int[][] m,int[][] s) {
        int i,j,k,d;
        for(d=3;d<=n;d++) {                                     //将问题划分为小规模d,3个站点、4个站点...n个站点
            for(i=1;i<=n-d+1;i++) {                             //子问题的初始站点
                j=i+d-1;                                        //子问题的终点站点
                for(k=i+1;k<j;k++) {                            //可停靠站点
                    int temp=m[i][k]+m[k][j];                   //在站点k停留
                    if(temp<m[i][j]) {                          //停留后的租金和比直达的租金便宜
                        m[i][j]=temp;
                        s[i][j]=k;                              //记录停靠点
                    }
                }
            }       
        }
    }

    /*求得停靠点,当s[i][j]=0时说明中间没有停靠点,输出站点j,否则划分为两个子问题*/
    public static void print(int i,int j,int[][] s) {
        if(s[i][j]==0) {
            System.out.print("——"+j);
            return;
        }
        print(i,s[i][j],s);
        print(s[i][j],j,s);
    }
}

程序运行结果如下:
这里写图片描述

4.6 矩阵连乘

import java.util.Scanner;

public class Test4_6 {
    static int n;
    public static void main(String[] args) {
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入矩阵的个数n:");
        n=scanner.nextInt();
        int[] p=new int[n+1];                          //记录矩阵行列
        int[][] m=new int[n+1][n+1];                   //最优值数组
        int[][] s=new int[n+1][n+1];                   //最优决策数组

        System.out.println("请依次输入每个矩阵的行数和最后一个矩阵的列数:");
        for(int i=0;i<=n;i++)
            p[i]=scanner.nextInt();
        matrixChain(p,m,s);                            //矩阵连乘求解函数
        print(1,n,s);
        System.out.println();
        System.out.println("最小计算量的值为:"+m[1][n]);
    }

    /*矩阵连乘求解函数*/
    public static void matrixChain(int[] p,int[][] m,int[][] s) {
        int i,j,r,k;
        for(r=2;r<=n;r++) {                            //2个矩阵连乘、3个矩阵连乘...n个矩阵连乘
            for(i=1;i<=n-r+1;i++) {                    //r个矩阵开始矩阵的下标
                j=i+r-1;                               //结束矩阵
                m[i][j]=m[i+1][j]+p[i-1]*p[i]*p[j];    //k=i时的乘法次数
                s[i][j]=i;                             //子问题的最优策略是i

                for(k=i+1;k<j;k++) {                   //对从i到j的所有策略求最优值
                    int temp=m[i][k]+m[k+1][j]+p[i-1]*p[k]*p[j];
                    if(temp<m[i][j]) {
                        m[i][j]=temp;
                        s[i][j]=k;
                    }
                }
            }
        }
    }

    /*最优解输出函数*/
    public static void print(int i,int j,int[][] s) {
        if(i==j) {
            System.out.print("A"+i);
            return;
        }
        System.out.print("(");
        print(i,s[i][j],s);
        print(s[i][j]+1,j,s);
        System.out.print(")");
    }
}

程序运行结果如下:
这里写图片描述

4.9 0-1背包问题

import java.util.Scanner;

public class Test4_9 {

    public static void main(String[] args) {
        int n,W;                                                    //n表示n个物品,W表示购物车容量      
        Scanner scanner=new Scanner(System.in);
        System.out.println("请输入物品的个数n:");
        n=scanner.nextInt();
        System.out.println("请输入购物车的容量W:");
        W=scanner.nextInt();

        int[] w=new int[n+1];                                       //存放所有物品的重量
        int[] v=new int[n+1];                                       //存放所有物品的价值
        int[][] c=new int[n+1][W+1];                                //表示前i个物品放入容量为j的购物车获得的最大价值

        System.out.println("请依次输入每个物品的重量w和价值v,用空格分开:");
        for(int i=1;i<=n;i++) {
            w[i]=scanner.nextInt();
            v[i]=scanner.nextInt();
        }

        //计算c[i][j]
        for(int i=1;i<=n;i++) {                                     //控制物品个数
            for(int j=1;j<=W;j++) {                                 //控制容量大小
                if(w[i]>j)                                          //物品重量大于购物车容量,则不放入第i个物品
                    c[i][j]=c[i-1][j];
                else 
                    c[i][j]=Math.max(c[i-1][j],c[i-1][j-w[i]]+v[i]);//比较放入此物品与不放入此物品哪个价值更大
            }
        }
        System.out.println("装入购物车的最大价值为:"+c[n][W]);

        //逆向构造最优解
        int[] x=new int[n+1];                                       //表示第i个物品是否放入购物车
        int j=W;
        for(int i=n;i>0;i--) {                                      //从最后一个物品开始判断
            if(c[i][j]>c[i-1][j]) {                                 //说明第i个物品放入购物车
                x[i]=1;
                j-=w[i];
            }
            else
                x[i]=0;                                             //说明第i个物品没有放入购物车
        }
        System.out.println("装入购物车的物品为:");
        for(int i=1;i<=n;i++) {
            if(x[i]==1)
                System.out.print(i+"  ");
        }
    }
}

程序运行结果如下:
这里写图片描述

  • 2
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值