背包问题动态规划算法java实现及分析

本文详细介绍了背包问题的动态规划算法实现过程,包括备忘录的填充与最优解的回溯,探讨了解空间的求解与表示方法。

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

背包问题是动态规划算法的典型问题,关键在于能够通过计算所有的子问题推导出问题的最优解,也就是说各个子问题之间没有互相约束的条件,比如选了3就不能选5,因此求解的过程也只是填写备忘录的过程。
背包问题还在于解空间的求解和表示,要知道备忘录只是求出了最优解的大小,但是无法记录最优解由哪些选项构成,这需要我们根据备忘录反向回溯,求解出解的空间。
要考虑到解的不唯一性,及又可能存在于两个项是完全一样,或者两个解的空间不一样的情况(如 3、4 和1、2、5)。


给出代码如下:其中多个值n,w,weight,value均可以修改

//背包算法问题求解,计算备忘录的值并回溯求出所有的解空间
//作者 barry 时间 2016/10/25
public class KnapSack {

    private static int n = 5;//总的背包数目
    private static int w = 11;//总重量
    private static int weight[]={1,3,5,6,7};//负重限制
    private static int value[]={10,10,22,22,24};//价值数组
    private static  int memory[][]=new int[n+1][w+1];//备忘录
    private static  String answer = new String();//答案字符串

    public KnapSack(){
        //初始化备忘录 为 0
        for(int i=0;i<n+1;i++){
            for(int j=0;j<w+1;j++){
                memory[i][j]=0;
            }
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub
        showMemory();//展示备忘录
        getMemory();//计算备忘录
        showMemory();//展示备忘录
        backTrace(n,w,answer);//回溯备忘录取得最优解

    }
    //计算备忘录
    //请注意备忘录从1开始计算而value和weight从0开始计算
    public static  void getMemory(){
        for(int i=1;i<n+1;i++){// n from 1 to 5
            for(int j=1;j<w+1;j++){//j from 1 to 11
                if(weight[i-1]>j) memory[i][j] = memory[i-1][j];
                else memory[i][j] = Math.max(memory[i-1][j], value[i-1]+memory[i-1][j-weight[i-1]]);
            }
        }
    }
    //展示备忘录
    public static void showMemory(){
        for(int i=0;i<n+1;i++){
            for(int j=0;j<w+1;j++){
                System.out.print(memory[i][j]);
            }
            System.out.println();
        }
        System.out.println();
    }

    //backtrace the best solutions from the x and y in memory 缺点 只能找到一个解,无法解决多个解的情况 可供参考
    /*public static void backTrace(int start_x,int start_y){
        if(memory[start_x][start_y]>0){
            if(memory[start_x][start_y]==memory[start_x-1][start_y]){//start_x may not in the best solution
                backTrace(start_x-1,start_y);
            }
            else{//start_x in the best solution
                System.out.print(start_x + "  ");
                backTrace(start_x-1,start_y-weight[start_x-1]);
            }
        }
    }*/

    //从x和y开始回溯备忘录,找到解的空间,并存放在字符串中输出
    public static void backTrace(int start_x,int start_y,String answer){
        if(start_y>=0&&memory[start_x][start_y]>0){//
            //start_x in the best solutions,start_x一定在最优解中,存入并计算
            if(memory[start_x][start_y]>memory[start_x-1][start_y]){
                //System.out.print(start_x + " ");
                answer += start_x + " ";
                backTrace(start_x-1,start_y-weight[start_x-1],answer);
            }
            //start_x not in the solutions,start_x一定不在最优解中,计算start_x-1
            else if((start_y>=weight[start_x-1])&&(memory[start_x-1][start_y]!=(value[start_x-1]+memory[start_x-1][start_y-weight[start_x-1]]))){
                backTrace(start_x-1,start_y,answer);
            }
            else{//both are possible,start_x此时都有可能存在于最优解,分别计算
                String answer_no = new String(answer);
                //not in 不在里面
                backTrace(start_x-1,start_y,answer_no);

                //in 在里面
                answer += start_x + " ";
                backTrace(start_x-1,start_y-weight[start_x-1],answer);  
            }
        }
        else if(start_y>=0){//start_y在计算过程中有可能小于0,避免此类情况,并且start_y>=0是结束的判断条件
            System.out.println(answer);
        }
    }
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值