算法设计与分析: 5-33 0-1背包问题

本文介绍了如何运用回溯法来解决经典的0-1背包问题。0-1背包问题要求在有限的背包容量下,选择物品以最大化总价值,每种物品只能选一次。文章提供了解决这个问题的Java实现,并给出了数据输入和输出的说明。

5-33 0-1背包问题


问题描述

试设计一个用回溯法搜索子集空间树的函数。该函数的参数包括结点可行性判定函数和上界函数等必要的函数,并将此函数用于解 0-1 背包问题。
0-1 背包问题描述如下:给定 n 种物品和一个背包。物品 i 的重量是 wiwi ,其价值为vivi ,背包的容量为 C。应如何选择装入背包的物品,使得装入背包中物品的总价值最大?
在选择装入背包的物品时,对每种物品 i 只有 2 种选择,即装入背包或不装入背包。不能将物品 i 装入背包多次,也不能只装入部分的物品 i。
0-1 背包问题形式化描述:给定C>0C>0wi>0wi>0vi>0vi>01in1≤i≤n,要求 n 元 0-1 向量(x1x2...xn)(x1,x2,...,xn)xi{01}xi∈{0,1}1in1≤i≤n,使得 i=1nwixiC∑i=1nwixi≤C, 而且i=1nvixi∑i=1nvixi 达到最大。

数据输入:
第一行有 2 个正整数 n 和 c。n 是物品数,c 是背包的容 量。接下来的 1 行中有 n 个正整数,表示物品的价值。第 3 行中有 n 个正整数,表示物品的 重量。


Java

package Chapter5HuiSuFa;

import java.util.Scanner;

public class BeiBao01 {

    private static int n,c;
    private static int[] x,bestx,w,p;
    private static int cw,cp,bestp;

    public static void main(String[] args){
        Scanner input = new Scanner(System.in);

        while (true){
            bestp = 0;
            cw = 0;
            cp = 0;

            n = input.nextInt();
            c = input.nextInt();

            w = new int[n+1];
            p = new int[n+1];
            x = new int[n+1];
            bestx = new int[n+1];

            for(int i=1; i<=n; i++)
                p[i] = input.nextInt();

            for(int i=1; i<=n; i++)
                w[i] = input.nextInt();

            backtrack(1);

            output();
        }
    }

    private static void backtrack(int t){
        if(t > n) record();
        else
            for(int i=0; i<=1; i++){
                x[t] = i;
                if(constraint(t) && bound(t)){
                    change(t);
                    backtrack(t+1);
                    restore(t);
                }
            }
    }

    private static void record(){
        if(cp > bestp){
            bestp = cp;
            for(int i=1; i<=n; i++)
                bestx[i] = x[i];
        }
    }

    private static boolean constraint(int t){
        if(x[t]==0 || x[t]==1 && cw+w[t]<=c) return true;
        else return false;
    }

    private static boolean bound(int t){
        if(x[t]==1 || x[t]==0 && upbound(t+1)>bestp) return true;
        else return false;
    }

    private static int upbound(int k){
        int cleft = c-cw;
        int b = cp;
        while (k<=n && w[k]<=cleft){
            cleft -= w[k];
            b += p[k];
            k++;
        }
        if(k <= n)
            b += p[k]*cleft/w[k];

        return b;
    }

    private static void change(int t){
        if(x[t] == 1){
            cw += w[t];
            cp += p[t];
        }
    }

    private static void restore(int t){
        if(x[t] == 1){
            cw -= w[t];
            cp -= p[t];
        }
    }

    private static void output(){
        System.out.println(bestp);
        for(int i=1; i<=n; i++)
            System.out.print(bestx[i]+" ");
    }
}

Input & Output

5 10
6 3 5 4 6
2 2 6 5 4
15
1 1 0 0 1 

5 10
5 3 6 6 4
6 2 2 4 5
15
0 1 1 1 0 

5 10
4 5 3 6 6
5 6 2 2 4
15
0 0 1 1 1 

5 10
3 6 6 4 5
2 2 4 5 6
15
1 1 1 0 0 

Reference

王晓东《计算机算法设计与分析》(第3版)P188

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值