当前位置:嗨网首页>书籍在线阅读

11-背包问题

  
选择背景色: 黄橙 洋红 淡粉 水蓝 草绿 白色 选择字体: 宋体 黑体 微软雅黑 楷体 选择字体大小: 恢复默认

13.10 0/1背包问题

问题描述

19.png 有n个重量为w1, w2, …, wn的物品,编号为1~n,价值分别为v1, v2, …, vn。要求从中选择物品装入重量为W的背包,这些物品只能装入背包或不装入背包,不能选择物品的某一部分装入背包,请设计算法使背包中的物品价值达到最大。

【分析】

假设物品的个数为n,则有2n个装入背包的组合方式。穷举所有组合方式,先从第一个组合开始,依次将该组合中的物品取出。若装入背包,则检查背包中物品的重量是否超过背包的限制,若不超过限制且当前物品总价值大于之前的组合,则更新表示物品最大价值的maxvalue变量并保存选择的物品编号。为了获取所有组合方式,可模拟二进制加法从00…0加到11…1。其中,每一位0和1对应于n个物品,表示是否选择装入背包,可用数组put[]依次存放这n个数字。例如,put[i]=1表示将第i+1个物品装入背包,put[i]=0表示第i+1个物品不装入背包。

第13章\实例13-10.cpp
/********************************************
*实例说明:0/1背包问题
*********************************************/
#include<stdio.h>
#define MAXN 20
typedef struct
{
    int weight[MAXN];
    int value[MAXN];
    int limitw;
    int num;
}Goods;
int Bin(int a[],int n);
void Knapsack(Goods *g,int select[]);
int BinTraverse(int a[],int n)
/*利用二进制模拟遍历数组中的每一位,达到枚举所有组合方式的目的*/
{
    int i,carry=0;
    a[0] += 1;
    for (i = 0; i < n; i++)
    {
        a[i] += carry;     
        carry = a[i] /2;   
        a[i] %= 2;         
        if (carry==0)
            return 0;
    }
    return carry;
}
void Knapsack(Goods *g,int select[])
/*使用枚举算法求解背包问题*/
{
   int i,flag;
   int put[MAXN];                      
   double maxvalue = 0,tw,tv;
   for (i = 0; i < g->num; i++)        /*初始化背包*/
       put[i] = 0;
   while(BinTraverse(put, g->num) == 0)
   {
       tw = 0;
       tv = 0;
       flag = 1;
       for (i = 0; i < g->num; i++)    
       {
           if (put[i] == 1)            
           {
               tw += g->weight[i];     
               tv += g->value[i];      
               if (tw > g->limitw)     
               {
                   flag = 0;           
                   break;
               }
           }
       }
       if(flag && maxvalue < tv)       
       {
           maxvalue = tv;              
           for(i = 0; i < g->num; i++) 
               select[i] = put[i];
       }
   }
}
void main()
{
    Goods g={{16,8,9,6,10},{20,12,18,9,10},35,5};/*初始化物品的重量、价值和背包的重量*/
    int totalweight,maxvalue,i;
    int select[MAXN];
    Knapsack(&g,select);
    totalweight=0;
    maxvalue=0;
    printf("背包的重量为%d\n",g.limitw);
    printf("物品数为%d\n",g.num);
    for(i=0;i<g.num;i++)
        printf("编号%d,重量:%d,价值:%d\n",i+1,g.weight[i],g.value[i]);
    printf("可将以下物品装入背包,达到价值最大:\n");
    for (i = 0; i < g.num; ++i)
    if (select[i])
    {
        printf("物品编号%d:重量为%d,价值为%d\n",i + 1,g.weight[i],g.value[i]);
        totalweight+=g.weight[i];
        maxvalue+=g.value[i];
    }
    printf("总重量为%d,总价值为%d\n",totalweight, maxvalue);
}

运行结果如图13.13所示。

381.png

图13.13 运行结果