动态规划-例题详解

本文深入探讨了背包问题的最优解求解方法,通过动态规划实现了物品选择以达到最大价值,同时输出了解决方案路径。此外,还讲解了不相邻数最大和问题,即小偷问题的数学版本,同样采用动态规划算法,输出最大值及选择的数列。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

//背包问题  最优解及其方案内容输出

//main方法
 int[] weight = {0, 1, 4, 3};
        int[] value = {0, 1500, 3000, 2000};
        int max = 4;
        int[][] marked = new int[4][5];
        int[][] op = OP(weight, value, 4, marked);
        System.out.println(op[3][4]);

//实现函数
int[][] optimise = new int[4][5];
       for (int i = 1; i < 4; i++) {  //表示每次能放的物品个数
           for (int j = 1; j <= max; j++) {  //表示每次能放的最大容量
               if (weight[i] <= j) {
                   if (optimise[i - 1][j]>=( value[i] + optimise[i - 1][j - weight[i]]))
                   {
                       optimise[i][j]=optimise[i - 1][j];
                   }else {
                       optimise[i][j]=value[i] + optimise[i - 1][j - weight[i]];
                       marked[i][j]=1;

                   }
                  // optimise[i][j] = Math.max(optimise[i - 1][j], value[i] + optimise[i - 1][j - weight[i]]); 
                  // 只能求最优解的结果,无法得到最优解的解决方案
               } else {
                   optimise[i][j] = optimise[i-1][j];
               }
           }
       }
       int i=optimise.length-1;//最优解的所在行数
       int j=optimise[0].length-1;//最优解的所在列数
       ArrayList<Integer> arrayList = new ArrayList<>();
       while (i>0){                      //这里开始从终点逆向寻找曾经的添加物品的足迹
           if (marked[i][j]==1){     //==1 代表曾经在这一轮有过物品的加入     !=1代表这一轮没有加入过物品且只是照搬上一次的最优解
              arrayList.add(i);
              j-=weight[i];  //曾经因为加入物品而质量增加,质量增加时的基础是 上一轮的j-weight[i]容量的最优解
           }
           i--;//无论是否 判断条件==1,最后都需要回溯到前一轮,(!=1时)默认回到最大容量之处,因为价格总和的最大值对应的容量就是如此...
       }
       Collections.reverse(arrayList);
       System.out.println(arrayList.toString());
       return optimise;
  

//求数组中不相邻数相加的最大值(小偷问题的数学版本)
//main

int[] ints={1,2,4,1,7,8,3};  //找出不相邻的数且之和为最大值
        int[] backed=new int[7];
      System.out.println(Optimise(ints,backed));
      


//实现函数
 public static int Optimise(int[] ints,int[] backed) {
        int[]  optimise = new int[ints.length];
        optimise[0]=1;
        optimise[1]=2;
        for (int i = 2; i <ints.length ; i++) {
               int a=ints[i]+optimise[i-2];  
               int b=optimise[i-1];
               if (a>b){
                   
                   if(i-2==0){         //由于i从2开始遍历,无法直接对0,1下标元素的backed判断,所以需要单独设置
                       backed[0]=-2;
                   }else if (i-2==1){   //为0,1下标开小灶....
                       backed[1]=-2;
                   }                    //为0,1下标开小灶....
                   
                   optimise[i]=a;
                  backed[i]=-2;
               }else {
                   optimise[i]=b;
                   backed[i]=-1;
               }
              // optimise[i]=a>=b?a:b;  用来求最优解结果最合适
        }
        int flag=optimise.length-1;
        ArrayList<Integer> list = new ArrayList<>();
        while (flag>=0){
            if (backed[flag]==-2){
                list.add(flag);
            }
            flag+=backed[flag];
        }
        Collections.reverse(list);
        System.out.println(list.toString());
        return optimise[ints.length-1];

    }
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值