动态规划(解决0-1背包问题)

本文深入讲解动态规划思想,探讨其与递归、分治算法的区别,通过0-1背包问题和轮船装载问题实例,展示如何将复杂问题分解为子问题求解,最终找到全局最优解。

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

动态规划思想

1.什么是动态故规划思想呢?
动态规划是一种算法设计的思想,主要是讲一个问题划分成几个更小的而问题进行求解,(其实很像递归)
2. 它的特点是什么?
它的各个子问题不是相互独立的,他们包含公共子问题,因此子问题的的解会被重复多次求解
3.动态规划与分治算法的异同点:
相同点: 做法是都会将一个大问题分解成多个子问题。
不同点: 以子问题是否相互独立 进行区别,动态规划子问题相互独立,分治算法中的被分解的那些子问题都是相互独立的;并通过递归的方式最终得到整个问题的解。

下边我们用一个0-1背包问题对动态规划问题进一步进行解析:
背包容量是c 6
不同物品对应的重量(w)分别为: 1 ,2, 3, 4
相对应的价值(value)分别为 : 2,3, 4, 6
求给背包中放置那些物品可保证价值最大?
分析: 我分先列张表,将所有情况都分析下
在这里插入图片描述

将背包划分六个子包,然后进行求解,然后推论出公式(从后往前):
w=4,v=6,j=1,2,3,时,dp[i][j]=dp[i+1][j]=0;
j=4时,dp[i][j]=max{0,v[i]+dp[i+1][j-w[i]]}=max{0,6+0}=6;
j=5 dp[i][j]类似的用(3)式
到w=3时,同样 按照此方法

装入背包的而物品最优,dp[i][j]: 表示选择了i个物品时的价值,(i 表示选择物品的个数,j 表示背包容量),
(1) dp[i][0]=dp[0][i]=0;
(2)j>w(i) dp[i][j]=v[i+1][j]
(3) j<=w(i) dp=max{dp[i+1][j],v[i]+ddp[i+1][j-w(i)]};
下边我们放代码

import java.util.Arrays;

/*dp[i][j]:装入物品最大价值
* i:选择物品的个数(行)
* j:背包容量(列)
* */
public class 动态规划求解背包问题 {
    static int []w={1,2,3,4};
    static int[]v={2,3,4,6};
    static int c=6;
    static int [][]dp=new int [w.length+1][c+1];
   static int [][]path=new int[w.length][c+1];
    public static void main(String[] args) {
        jude(w,v,c,dp);
        System.out.println();
    }
    public static void jude(int[]w,int[]v,int c,int[][]dp){
        int n=w.length-1;
        for (int j = 1; j <=c; j++) {
            if(w[n]>j){
              dp[n][j]=0;
            }else {
                dp[n][j]=v[n];
            }
        }
        for (int i = n-1; i >=0; i--) {//代表行
            for (int i1 = 1; i1 <=c; i1++) {//代表列
               if(w[i]>i1){
                    dp[i][i1]=dp[i+1][i1];
                }if(w[i]<=i1){
                    dp[i][i1]=Math.max(dp[i+1][i1],v[i]+dp[i+1][i1-w[i]] );
                }
            }
        }


            for (int i = 0; i < w.length; i++) {
                for (int i1 = 1; i1 <=c; i1++) {
          System.out.print(dp[i][i1]+"\t ");
                }
                System.out.println();
            }
            //打印路径
        for (int i = 0; i < w.length-1; i++) {
            if (dp[i][c] != dp[i + 1][c]) {
                //选择了wupin
                System.out.println(w[i] + " ");
                c -= w[i];
            }
        }
        if(dp[w.length-1][c]>0){
            System.out.println(w[w.length-1]+" ");
        }
        System.out.println();



        }
    }



运行结果:
0  0  0  0  0  0  0  0 
0  2  3	 5	 6	 8	 9	 
0  0   3  4	 6	 7	 9	 
0  0   0  4	 6	 6	 6	 
0  0   0  0	 6	 6	 6	
2 
4




2.动态规划解决轮船装在问题
解决方法同上,我们尽可能将承重能力大的船装满,这里没有价值上的考虑


public class 动态规划解决轮船装载 {
    static int []w={8,9,10,13,7,14,12,5};
    static int c1=50;
    static int c2=28;
    static int [][]dp=new int[w.length][c1+1];
    public static void main(String[] args) {
        jude();
        System.out.println();
    }
    public static void jude() {
        int n = w.length - 1;
        for (int j = 1; j <= c1; j++) {
            if (w[n] > j) {
                dp[n][j] = 0;
            } else {
                dp[n][j] = w[n];
            }
        }
        for (int i = n - 1; i >= 0; i--) {
            for (int j = 1; j <= c1; j++) {
                if (w[i] > j) {
                    dp[i][j] = dp[i + 1][j];
                } else {
                    dp[i][j] = Math.max(dp[i + 1][j], w[i] + dp[i + 1][j - w[i]]);
                }
            }
        }
        for (int i = 0; i < w.length; i++) {
            for (int j = 1; j <= c1; j++) {
                System.out.print(dp[i][j] + "\t ");
            }
            System.out.println();
        }
        int[] x = new int[w.length];
        int c1w = c1;
        for (int i = 0; i < w.length - 1; i++) {
            if (dp[i][c1w] != dp[i + 1][c1w]) {
                x[i] = 1;
                System.out.print(w[i] + " ");
                c1w -= w[i];
            }
        }

        if (dp[w.length - 1][c1] > 0) {
            System.out.println(x[w.length - 1] = 1);
        }
        System.out.println("装入c1:" + c1);
        for (int i = 0; i < x.length; i++) {
            if (x[i] == 1) {
                System.out.print(w[i] + " ");
            }
        }
        System.out.println();

        System.out.println("装入c2:" + c2);
        for (int i = 0; i < x.length; i++) {
            if (x[i] == 0) {
                System.out.print(w[i] + " ");

            }
        }

    }
}


这个结果的二维数组太大我就不放结果了。
总结:动态规划这块就时大问题就化成哥哥子问题的解,最后求解出总最优解。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值