Day 14 分治 动态规划

分治:把问题分为多个子问题 求出子问题的解 合并就为问题的解 (分治中每个子问题之间不存在相互依赖) 案例汉诺塔

public class FenZhi {
    public static void main(String[] args) {
        hnt(3,'A','B','C');
    }
    //汉诺塔
    public static void hnt(int count,char a,char b,char c ){
        if (count==1){
            System.out.println("移动第:"+count+"块,从"+a+"->"+c);
            return;
        }
        //count = 3 进入 hnt(count=2 , a . c , b) 在count等于2这个空间中 b是c c是b
        // 然后再hnt(count=1,a,c,b)
        // 在count等于1时cb再次互换 使得他们恢复自己 b=b c=c 此时count = 1
        // 然后触发if条件输出第1个从a - c (因为此时cb的值经过两次调换恢复了本来的值)再触发return
        //然后回溯到count=2 这个空间中 然后向下运行输出“System.out.println("移动第:"+count+"块,从"+a+"->"+c);” 这个语句
        //在count=2这个空间中cb的值是互换的 所以输出第2个从a-b
        // 然后继续向下 执行hnt(count-1,b,a,c); 再次开辟一个count = 1的空间并调换当前b(当前b的值为c)跟当前a的值
        //然后再次触发if 然后输出第一个盘从a(a此时为b的值 而b此时为c的值 所以a=c) - c(c此时为b的值) 实际输出c -b;再触发return
        // 然后回溯至count=2这个空间 发现这个空间已执行完毕
        //再次回溯至count = 3这个空间 然后向下运行 " System.out.println("移动第:"+count+"块,从"+a+"->"+c);" 此时abc的值是正常的
        //所以输出第3块从a-c 然后 执行“hnt(count-1,b,a,c);”
        // 再次开辟count = 2的空间并调换ab的值 在新开辟的count =2的空间中 再次执行hnt(count-1,a,c,b);
        //再次开辟count = 1的空间并调换现在b(此时表示a) - c的值
        //在新开辟的count = 1这个空间中 a=b  b = c  c = a 然后触发if输出第1块从a(b) - c(a) 即b - a
        //然后再次回溯至count = 2的空间中向下执行 此时a=b b=a c=c  再次输出a(b)-c 实际b-c
        //然后再次开辟count=1的空间 并调换当前a-b的值 此时(新的count=1的空间中) a=a b=b c=c
        // 因为他是在a=b b=a c=c的情况下调换的ab的值 所以恢复了
        //然后触发if语句 输出第1块从a - c 再触发return 然后回溯至count = 2的空间 发现此空间执行完毕
        // 再回溯至count=1的空间中 发现这个空间也执行完毕 所以方法停止
        hnt(count-1,a,c,b);
        System.out.println("移动第:"+count+"块,从"+a+"->"+c);
        hnt(count-1,b,a,c);
    }
}

动态规划:与分治相似 但动态规划分解出的子问题之前 是需要相互依赖的

案例 01背包问题

package DynamicPlanning;

public class backPack {
    public static void main(String[] args) {
        //01背包问题  - 动态规划
        int []weight = {1,3,4};//商品所占用的重量
        int []value = {1500,2000,3000};//商品的价值
        int m = 4;//背包的最大容量
        int n = value.length;//商品的数量(种类数量)
        //用来求结果 有物品的种类数量+1行 每一行都表示一个商品 +1是因为有第0行 0行代表没有商品
        //有当前背包最大容量+1列 也是有第0列   dp[][] 代表当前背包容量和当前商品种类数量的情况下 背包装入的最大价值
        //设置背包 这个步骤可以忽略 因为数组的初始值就是0  这个步骤代表吧商品数量为零的时候的所有背包容量的情况全部为0
        int [][]dp = new int[n+1][m+1];
        //该数组用来记录你装入了那个商品
        int [][]sp = new int[n+1][m+1];
        for (int i=0;i<n+1;i++){
            dp[i][0] = 0;
        }
        for (int i=0;i<m+1;i++){
            dp[0][i] = 0;
        }
        //填充表格情况 求结果 不遍历第0行和第0列的情况 因为结果一定为0
        for (int i=1;i<dp.length;i++){
            for (int j = 1; j < dp[i].length; j++) {
                //如果当前商品的重量 > 当前背包的重量 也就是当前商品无法放入当前背包
                if (weight[i-1] > j){//因为dp中有0的存在而weight中没有 所有这里要-1 j代表当前背包的容量
                    dp[i][j] = dp[i-1][j];//那么dp[当前商品数量][当前背包容量]的价值 就等于dp[上一个商品数量][当前背包容量]的价值
                }else{//否则就是 当前商品的重量=或者<当前背包容量
                    //如果 dp[上一个商品数量][当前背包容量]的价值 < 当前这个商品的价值 + dp[上一个商品数量][(当前背包容量 - 当前商品重量)]的价值
                    if (dp[i-1][j] < value[i-1] + dp[i-1][j-weight[i-1]]){
                        //dp = 当前这个商品的价值 + dp[上一个商品数量][(当前背包容量 - 当前商品重量)]的价值
                        dp[i][j] = value[i-1] + dp[i-1][j-weight[i-1]];
                        //表示 这个时候装入了当前商品
                        sp[i][j] = 1;
                    }else{
                        dp[i][j] = dp[i-1][j];
                    }
                }
            }
        }
        for (int i=0;i<dp.length;i++){
            for (int j = 0; j < dp[i].length; j++) {
                System.out.print(dp[i][j]+"\t");
            }
            System.out.println();
        }
        System.out.println("装入情况");
        for (int i=0;i<sp.length;i++){
            for (int j = 0; j < sp[i].length; j++) {
                System.out.print(sp[i][j]+"\t");
            }
            System.out.println();
        }

        int x = n;//商品的种类数量
        int y = m;//背包的最大容量
        while (x>0&&y>0){
            if (sp[x][y] == 1){
                System.out.println("装入了商品"+x);
                y = y - weight[x-1];
            }
            x--;
        }

    }
}

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值