数据结构-五大基本算法-动态规划

用于求解某种最优性质的问题,动态规划与分治法类似。

例题:

0-1 背包问题:有n种物品和一背包,物品i的重量是wi,其价值为vi,其中wi 和 vi均为正整数,背包的容量为w,现需要考虑如何 选择装入背包的物品,使得装入背包中物品的总价值最大?分析一下:

 

 

目标函数:从i个物品 累计求和 i个物品 = n 的总价值

约束条件:当 i个物品的重量 <=背包的容量,x 取值 0【不放入】,1 【放入】

 

分析下这三种情况:

第一种情况:如果 i=0 表示没有放入物体,w=0,表示重量为0 所以为 0

第二种情况: 当 当前物品的重量大于背包总重量 ,当前物体不放入背包

第三种情况,当 当前物品的 重量小于背包总重量,且 判断,如果当前物品放入背包,求当前物品放入背包后的 总价值 或 当前物品不放入背包,求背包可能容纳的总价值,MAX二者取一。

i 物品 \ W 重量

0

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

1

0

0

0

4

4

4

4

4

4

4

4

4

4

4

4

4

4

4

2

0

0

0

4

5

5

5

9

9

9

9

9

9

9

9

9

9

9

3

0

0

0

4

5

5

5

10

10

10

14

14

14

14

19

19

19

19

4

0

0

0

4

5

5

5

10

11

11

14

15

16

16

19

21

21

21

5

0

0

0

4

5

5

5

10

13

13

14

15

17

18

19

21

23

24

分析表格:

当重量 w 越来越大时,我们可以判断 物品 i 是否能放入 每一次变化的 递增+1 中,一共递增 17次,因为我们可容纳的重量是17

java 求出最优解:

 


/**
 * @Author wuxiaotian
 * @Date 2021/8/26 11:00
 * @Version C1.4
 */
public class Test03 {
     void OutPutKnapsackDp(int n,int W, int[] weights,int[] values,int[][] c){
         int[] x = new int[5]; //n 表示所有的 物品总数
         int i = 0;
         for ( i = n; i > 0; i--) {
             if(W - 1 >= 0) {
                 if (c[i][W - 1] == c[i - 1][W - 1]) { //重量为w 的最优选择的背包中不包含该物品 判断当前这个物品 放入和不放入价值相等得话 就不放入
                     x[i - 1] = 0; //不放入该物品
                 } else {
                     x[i - 1] = 1; //放入该物品
                     System.out.println("总总量:" + W + "当前物品重量:" + weights[i] + "剩余重量:" + (W - weights[i]));
                     W = W - weights[i]; //更新背包目前的最大容量 总容量 - 当前物品容量
                 }
             }
           
         }


         if(c[1][W] == 0){ //第一个物品不放入背包
             x[0] = 0;
         }else{
             x[0] = 1; //第一个物品放入背包
         }

         for (int j = 0; j <n; j++) {
             if(x[j] == 1){
                 System.out.println(String.format("重量为%d: 价值为%d:",weights[j+1],values[j+1]));
             }
         }
     }

    public static void main(String[] args) {
        Test03 test03 = new Test03();
        int n = 4; //物品个数
        int W = 17; //总容量
        int[] weights = new int[] {3,4,7,8,9};
        int[] values = new int[] {4,5,10,11,13};

        int [][] c =new int[5][17];
        c[0] = new int[] {0 ,0 ,4, 4 ,4 ,4, 4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4 ,4, 4};
        c[1] = new int[] {0 ,0 ,4, 5, 5, 5, 9, 9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9 ,9};
        c[2] = new int[] {0, 0, 4, 5, 5, 5, 10, 10, 10, 14, 14, 14, 14, 19, 19, 19, 19};
        c[3] = new int[] {0, 0, 4, 5, 5, 5, 10, 11, 11, 14, 15, 16, 16, 19, 21, 21, 21};
        c[4] = new int[] {0, 0, 4, 5, 5, 5, 10, 13, 13, 14, 15, 17, 18, 19, 21, 23, 24};

        for (int i = 0; i <5; i++) {
            for (int j = 0; j < weights.length; j++) {
                c[i][j] = j;
            }
        }
        test03.OutPutKnapsackDp(n,W,weights,values,c);
    }
}

由于时间原因,以上算法可能不够精简,仅仅实现了功能,小伙伴们有更好的算法可以私聊我,一起学习丫

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值