(POJ-1276) Cash Machine (binary optimization + multiple backpacks)

Topic link: 1276 -- Cash Machine

The meaning of the question: first give you a backpack capacity, and then give you the volume and quantity of each item of n items, what is the maximum volume of items that can be loaded?

After binary optimization, multiple knapsacks are equivalent to 01 knapsacks. What is binary optimization? That is to say, there are m pieces of an item. In the process of solving the multi-knapsack problem, we will traverse how many pieces to take in turn, so the complexity is a bit high, and binary optimization means that 2^s items are taken as one item, so that the original You need to take 2^s times. Now you only need to take it once , and the complexity will be greatly reduced. How to prove the correctness of this?

We assume that the optimal answer contains k items of this kind, and then we divide m into the sum of several consecutive powers of 2, that is, m=1+2+4+8+...+2^s+p( 0<=p<=2^(s+1)), a total of s+2 numbers, where p is not necessarily a power of 2, then k must be represented by several of these s+2 numbers, because The sum of these numbers is greater than or equal to k and the power of two is continuous, so any number less than or equal to m can be represented by these numbers . Now give a proof for this place:

(1) k<=2^(s+1)-1, at this time, write the binary representation of k, and take the number of items when the first digit is 1. For example, the binary expression of k is 10011(s>=5 ), at this time, since the 1st, 2nd, and 5th bits in the binary representation are 1, we can take the 1st, 2nd, and 5th items, so that k can be represented

(2) 2^(s+1)<=k<=p+2^(s+1)-1=m, then kp<=2^(s+1)-1, which means we can First take out p items, and then write out the binary representation of the remaining items to be taken, and then the same as above, whichever digit in the kp binary representation is 1 will take the first item

With this, this problem becomes an ordinary 01 knapsack problem. The method of decomposing m items into several consecutive powers of two is shown in the code:

#include<cstdio>
#include<iostream>
#include<cstring>
#include<vector>
#include<algorithm>
#include<map>
#include<cmath>
#include<queue>
using namespace std;
const int N=1e5+10;
int f[N],v[N];
int main()
{
	int V,n;
	while(scanf("%d",&V)!=EOF)
	{
		scanf("%d",&n);
		memset(f,0,sizeof f);
		int cnt=0;
		for(int i=1;i<=n;i++)
		{
			int s,t;
			scanf("%d%d",&s,&t);
			for(int j=1;j<=s;j<<=1)//将物品数目拆分成若干个2进制(最后一个物品可能不是二进制数,但不影响 ) 
			{
				v[++cnt]=j*t;
				s-=j;
			}
			if(t)
				v[++cnt]=t*s;
		}
		for(int i=1;i<=cnt;i++)
			for(int j=V;j>=v[i];j--)
				f[j]=max(f[j],f[j-v[i]]+v[i]);
		printf("%d\n",f[V]);
	}
	return 0;
}

Guess you like

Origin blog.csdn.net/AC__dream/article/details/123912843