多重背包的二进制分解思想

原创 2012年02月07日 22:13:32

在背包九讲里面将多重背包转化为01背包,并且进行时间优化,有利用到一个二进制分解的思想。

下面是在网上搜索之后得到的一个关于二进制分解思想的讲解和实现

多重背包二进制分解思想讲解

/**
    在这之前,我空间好像转过一个背包九讲,现在我就只对
    01背包和多重背包有点印象了

    先说下 01 背包,有n 种不同的物品,每个物品有两个属性
    size 体积,value 价值,现在给一个容量为 w 的背包,问
    最多可带走多少价值的物品。

    int f[w+1];   //f[x] 表示背包容量为x 时的最大价值
    for (int i=0; i<n; i++)
        for (int j=w; j>=size[i]; j++)
            f[j] = max(f[j], f[j-size[i]]+value[i]);

    如果物品不计件数,就是每个物品不只一件的话,稍微改下即可
    for (int i=0; i<n; i++)
        for (int j=size[i]; j<=w; j++)
            f[j] = max(f[j], f[j-size[i]]+value[i]);

    f[w] 即为所求

    初始化分两种情况
    1、如果背包要求正好装满则初始化 f[0] = 0, f[1~w] = -INF;
    2、如果不需要正好装满 f[0~v] = 0;

    多重背包问题要求很简单,就是每件物品给出确定的件数,求
    可得到的最大价值

    多重背包转换成 01 背包问题就是多了个初始化,把它的件数C 用
    分解成若干个件数的集合,这里面数字可以组合成任意小于等于C
    的件数,而且不会重复,之所以叫二进制分解,是因为这样分解可
    以用数字的二进制形式来解释
    比如:7的二进制 7 = 111 它可以分解成 001 010 100 这三个数可以
    组合成任意小于等于7 的数,而且每种组合都会得到不同的数
    15 = 1111 可分解成 0001  0010  0100  1000 四个数字
    如果13 = 1101 则分解为 0001 0010 0100 0110 前三个数字可以组合成
    7以内任意一个数,加上 0110 = 6 可以组合成任意一个大于6 小于13
    的数,虽然有重复但总是能把 13 以内所有的数都考虑到了,基于这种
    思想去把多件物品转换为,多种一件物品,就可用01 背包求解了。


    看代码:
    int n;  //输入有多少种物品
    int c;  //每种物品有多少件
    int v;  //每种物品的价值
    int s;  //每种物品的尺寸
    int count = 0; //分解后可得到多少种物品
    int value[MAX]; //用来保存分解后的物品价值
    int size[MAX];  //用来保存分解后物品体积

    scanf("%d", &n);    //先输入有多少种物品,接下来对每种物品进行分解

    while (n--) {   //接下来输入n中这个物品
        scanf("%d%d%d", &c, &s, &v);  //输入每种物品的数目和价值
        for (int k=1; k<=c; k<<=1) { //<<右移 相当于乘二
            value[count] = k*v;
            size[count++] = k*s;
            c -= k;
        }
        if (c > 0) {
            value[count] = c*v;
            size[count++] = c*s;
        }
    }

    现在用count 代替 n 就和01 背包问题完全一样了

下面是利用上面的讲解,对HDOJ 2191进行解答,代码如下:

#include <iostream>
using namespace std;

int main()
{
	int nCase,Limit,nKind,i,j,k,
		v[111],w[111],c[111],dp[111];
	//v[]存价值,w[]存尺寸,c[]存件数
	//在本题中,价值是米的重量,尺寸是米的价格

	int count,Value[1111],size[1111];
	//count存储分解完后的物品总数
	//Value存储分解完后每件物品的价值
	//size存储分解完后每件物品的尺寸

	cin>>nCase;
	while(nCase--)
	{	
		count=0;
		cin>>Limit>>nKind;
		for(i=0;i<nKind;i++)
		{
			cin>>w[i]>>v[i]>>c[i];
			
			//对该种类的c[i]件物品进行二进制分解
			for(j=1;j<=c[i];j<<=1)
			{
				//<<右移1位,相当于乘2
				Value[count]=j*v[i];
				size[count++]=j*w[i];
				c[i] -= j;
			}
			if(c[i] > 0)
			{
				Value[count]=c[i]*v[i];
				size[count++]=c[i]*w[i];
			}
		}

		//经过上面对每一种物品的分解,
		//现在Value[]存的就是分解后的物品价值
		//size[]存的就是分解后的物品尺寸
		//count就相当于原来的n

		//下面就直接用01背包算法来解
		memset(dp,0,sizeof(dp));

		for(i=0;i<count;i++)
			for(j=Limit;j>=size[i];j--)
				if(dp[j] < dp[j-size[i]] + Value[i])
					dp[j]=dp[j-size[i]]+Value[i];
		
		cout<<dp[Limit]<<endl;
	}
	return 0;
}

在背包九讲里面,他的实现方法和这个是不一样的,他是利用01背包和完全背包来配合实现的,下面是那个版本的实现

/*
HDOJ 2191
多重背包用二进制转化的思想,进行优化
*/

#include <iostream>
using namespace std;

int weight[110],Value[110],num[110];
int f[1100];
int limit;

inline void ZeroOnePack(int w,int v)
{
	int j;
	for(j=limit;j>=w;j--)
	{
		if(f[j-w]+v > f[j])
			f[j]=f[j-w]+v;
	}
}

inline void CompletePack(int w,int v)
{
	int j;
	for(j=w;j<=limit;j++)
	{
		if(f[j-w]+v > f[j])
			f[j]=f[j-w]+v;
	}
}

inline void MultiplePack(int w,int v,int amount)
{
	if(amount * w >= limit)
	{
		CompletePack(w,v);
		return ;
	}
	for(int k=1;k<amount;k<<=1)
	{
		ZeroOnePack(k*w,k*v);
		amount -= k;
	}
	ZeroOnePack(amount*w,amount*v);
}

int main()
{
	int T,n;
	cin>>T;
	while(T--)
	{
		cin>>limit>>n;
		
		for(int i=0;i<n;i++)
			cin>>weight[i]>>Value[i]>>num[i];
		
		memset(f,0,sizeof(f));
		
		for(i=0;i<n;i++)
			MultiplePack(weight[i],Value[i],num[i]);
		
		cout<<f[limit]<<endl;
	}
	return 0;
}


多重背包二进制分解思想讲解

转载自 在背包九讲里面将多重背包转化为01背包,并且进行时间优化,有利用到一个二进制分解的思想。 下面是在网上搜索之后得到的一个关于二进制分解思想的讲解和实现 多重背包二进制分解思想...
  • weinierzui
  • weinierzui
  • 2014年04月14日 12:59
  • 3218

多重背包二进制优化的思考

其实说白了我们最朴素的多重背包做法是将有数量限制的相同物品看成多个不同的0-1背包。这样的时间复杂度为O(V*Σn(i)) V为空间容量,n(i)为每种背包的数量限制。如果这样会超时,我们就得考虑更优...
  • xky0714
  • xky0714
  • 2013年08月19日 22:36
  • 1076

51Nod 1086 背包问题 V2(二进制多重背包)

题目链接:51Nod 1086 背包问题 V2问题描述: 有N种物品,每种物品的数量为C1,C2……Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2……Wn(Wi为整数),与之...
  • Dextrad_ihacker
  • Dextrad_ihacker
  • 2016年03月18日 14:27
  • 520

hdu 2844 coins (多重背包+二进制优化)

给出n种面值的硬币,以及它们的数量,问能组成不超过m的面值有多少个。 样例2解释: 2 5 1 4 2 1 面值为1的硬币2个,面值为4的硬币1个。能组成的面值有1、2、4、5、6。其中...
  • u014679804
  • u014679804
  • 2015年10月04日 14:57
  • 268

POJ1014-Dividing【DFS】【多重背包+二进制优化】

  • 2011年08月04日 23:17
  • 7KB
  • 下载

多重背包问题的二进制分解思想

/** 在这之前,我空间好像转过一个背包九讲,现在我就只对 01背包和多重背包有点印象了 先说下 01 背包,有n 种不同的物品,每个物品有两个属性 size 体积,...
  • zcube
  • zcube
  • 2015年09月07日 19:53
  • 2549

多重背包二进制优化的思考

其实说白了我们最朴素的多重背包做法是将有数量限制的相同物品看成多个不同的0-1背包。这样的时间复杂度为O(V*Σn(i)) V为空间容量,n(i)为每种背包的数量限制。如果这样会超时,我们就得考虑更优...
  • xky0714
  • xky0714
  • 2013年08月19日 22:36
  • 1076

多重背包二进制优化模板分析

#include #include #include #define N 1000 //物品个数 #define M 100000000 //所有物品可能的最大价值 int ...
  • mystery_guest
  • mystery_guest
  • 2016年07月11日 09:08
  • 322

51Nod 1086 背包问题 V2(二进制多重背包)

题目链接:51Nod 1086 背包问题 V2问题描述: 有N种物品,每种物品的数量为C1,C2……Cn。从中任选若干件放在容量为W的背包里,每种物品的体积为W1,W2……Wn(Wi为整数),与之...
  • Dextrad_ihacker
  • Dextrad_ihacker
  • 2016年03月18日 14:27
  • 520

多重背包二进制分解思想讲解

转载自 在背包九讲里面将多重背包转化为01背包,并且进行时间优化,有利用到一个二进制分解的思想。 下面是在网上搜索之后得到的一个关于二进制分解思想的讲解和实现 多重背包二进制分解思想...
  • weinierzui
  • weinierzui
  • 2014年04月14日 12:59
  • 3218
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:多重背包的二进制分解思想
举报原因:
原因补充:

(最多只允许输入30个字)