0-1背包问题(java版)

问题描述:
给定n种物品和一背包。物品i的重量是wi,其价值为vi,背包的容量为C。问应如何选择装入背包的物品,使得装
入背包中物品的总价值最大?

对于一种物品,要么装入背包,要么不装。所以对于一种物品的装入状态可以取0和1.我们设物品i的装入状态为xi,xi∈ (0,1),此问题称为0-11背包问题。

`
public class PacketQuestion {
public static void main(String[] args) {
int c = 10;//背包的总容量
int[] w = {0,2,2,6,5,4};//每个物体的重量
int[] v = {0,6,3,5,4,6};//每个物理的价值

    int n = w.length;//计算物体的个数

    int x[] = new int[n];//x[i]的值要么为0要么为1,1表示放当前i的物品,0表示不放当前i的物品

    int[][] m = new int[n][11];//存放可能性的二维数组
    packet0_1(m,w,v,c);//该方法就是构造最优解的那个二维数组m

    //输出构造的二维数组的结果
    for (int i = 1; i < m.length; i++) {
        for (int j = 0; j < m[i].length; j++) {
            System.out.print(m[i][j] + " ");
        }

        System.out.println();
    }
    /*
     *输出结果为:
     0 0 6 6 9 9 12 12 15 15 15 
     0 0 3 3 6 6 9  9  9  10 11 
     0 0 0 0 6 6 6  6  6  10 11 
     0 0 0 0 6 6 6  6  6  10 10 
     0 0 0 0 6 6 6  6  6  6  6 
     */

    //根据构造的二维数组,给x赋值
    answer(m,w,c,x);

    System.out.print("是否装物品的数组:");

    for (int i = 0; i < x.length; i++) {
        System.out.print(x[i] + " ");
    }
    /*
        结果为:是否装物品的数组(x数组的值为):0 1 1 0 0 1
     */
    //总价值
    int value = getValues(v,x);

    System.out.print("最高总价值 : ");
    System.out.println(value);
    /*
     * 总价值 : 15
     */
}

private static int getValues(int[] v, int[] x) {
    int value = 0;//最初的价值为0

    for (int i = 0; i < x.length; i++) {
        value += v[i] * x[i];//当前物品的价值 * 该物体是否被放。
    }
    return value;
}

//根据最优解的结果为x数组赋值,顺序是从上到下,从左到右。x数组的值有两个,1表示选该物体,0表示不选该物体
private static void answer(int[][] m,int[] w, int c, int[] x) {
    int j = c;//最初的总重量
    int i = 1;
    int n = w.length;
    //遍历每一行的值
    for (i = 1; i < n-1; i++) {
        //如果承重为j的包所放当前物体最大价值等于下一个物体的最大价值,说明该物体没有被放进包里,所以x[i] = 0
        if (m[i][j] == m[i+1][j]) {
            x[i] = 0;
        }else{//反之,放入包里了,x[i]置1,包的空间数减去当前物体的重量
            x[i] = 1;
            j = j - w[i];//放该物体后,剩余的空间
        }

    }
    x[n-1] = m[i][j] != 0 ? 1 : 0;   //承重为j的包所放当最后一个物体的价值不为0,说明放了最后一个物体,反之没有放。
}

private static void packet0_1(int[][] m, int[] w, int[] v, int c) {
    int n = m.length;
    //给二维数组的最后一行赋值
    //因为最后一行只存放最后一个物体,所以背包承重大于物体重量,就放该物体,二维数组的就就是物体的价值,否则就不放该物体
    for (int i = 0; i <= c; i++) {
        //放该物体
        if (i >= w[n-1]) {
            m[n-1][i] = v[n-1];
        }else{//不放该物体
            m[n-1][i] = 0;
        }
    }

    //从倒数第二行开始向前为每个二维数组对应的值赋值
    for (int i = n - 2; i > 0; i--) {//控制行值
        for (int j = 0; j <= c; j++) {//控制列值,也就是当前包的承重
            if (j < w[i]) {
                //如果当前背包的承重小于当前物体的重量,那么当前背包的承重就等于下一个位置的值
                m[i][j] = m[i+1][j];
            }else{
                //否则就比较该位置放该物体,与不放该物体的价值哪个大,哪个大就放哪个
                /*
                 * m[i+1][j - w[i]] + v[i]:
                 * v[i]是当前物体的价值
                 * m[i+1][j - w[i]]是除去当前物体的重量后背包能放的最大重量,第j-w[i]的背包能放的最大价值就是i+1列
                 * m[i+1][j]:表示不放该物体时背包能放的最大价值
                 */
                m[i][j] = Math.max(m[i+1][j - w[i]] + v[i], m[i+1][j]);
            }
        }

    }
}

}

`

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值