Let's introduce the notion of a mask that represents a subset of items to be shipped. For example, the mask mask = 5 = 101_2 specifies the subset containing the -th and -nd items (items are numbered from zero).
For each subset, we compute its total weight, which determines the shipping cost. If this weight is exactly grams, then since p \le 1000, it is always beneficial to use the special offer.
Let MinCost[mask] denote the minimum cost (in euros) of shipping the subset of items represented by . Then for any mask that is a subset of , the following relation holds:
Since the mask 2^n - 1 corresponds to the entire set of items, the answer to the problem will be the value MinCost[2^n - 1].
Theorem. Enumerating all masks and all of their submasks takes O(3^n) time.
Proof 1. Consider the -th bit. There are three possible cases for it:
it is included in the mask and included in the submask ;
it is included in the mask but not included in the submask ;
it is included in neither the mask nor the submask ;
There are bits in total, so the total number of different combinations is 3^n.
Proof 2. Let a mask contain set bits. Then it has exactly 2^k submasks. The number of masks of length with exactly set bits is C_n^k. Therefore, the total number of combinations is
Algorithm implementation
We'll store the item weights in the array . In the cell MinCost[mask], we'll store the minimum shipping cost for the subset of items represented by the mask .
int m[15], MinCost[1 << 14];Read the input data.
scanf("%d %d",&n,&p);
for (i = 0; i < n; i++) scanf("%d",&m[i]);In the variable , iterate over all possible masks from to 2^n - 1.
for (mask = 0; mask < (1 << n); mask++)
{Store in the variable the total weight of the subset of items corresponding to the mask . To do this, examine the binary representation of : if the bit at position is , then add the weight of the -th item to .
for (Cost = i = 0; i < n; i++)
if (mask & (1 << i)) Cost += m[i];If the value of is strictly equal to , then since the problem states that p \le 1000, assign the value to .
if (Cost == 1000) Cost = p;Store the computed shipping cost in the corresponding cell of the array.
MinCost[mask] = Cost;
}For each mask , iterate over all subsets x \sub mask (the mask is a subset of if and only if mask~AND~x equals ). If we subtract the set corresponding to from the set corresponding to , we get the set with mask mask~XOR~x.
For example, if mask = 1101_2 and x = 1001_2, then mask~XOR~x = 100_2, which corresponds to the set-theoretic operation \{1, 3, 4\} \setminus \{1, 4\} = \{3\}.
for (mask = 0; mask < (1 << n); mask++)
for (x = 0; x < mask; x++)Recompute the value of MinCost[mask] according to the recurrence relation given in the problem analysis.
if ((mask & x) == x)
MinCost[mask] = min(MinCost[mask],MinCost[mask^x] + MinCost[x]);Print the answer, which is stored in the cell MinCost[2^n - 1].
printf("%d\n",MinCost[(1 << n) - 1]);Algorithm implementation with complexity O(3^n)
Declare the constant and the arrays.
#define MAX 0xFFFFFFFF
unsigned int m[15], MinCost[1 << 14];For a mask , it is necessary to iterate over all its submasks and find the minimum among all possible values
Due to the symmetry of this sum, it is sufficient to consider only those submasks for which the condition sub \ge mask~XOR~sub holds.
unsigned int FindCost(int mask)
{
if (MinCost[mask] != MAX) return MinCost[mask];
// sub перебирает все подмаски маски mask
for (int sub = (mask - 1) & mask;
sub >= mask ^ sub; sub = (sub - 1) & mask)
MinCost[mask] =
min(MinCost[mask], FindCost(sub) + FindCost(mask ^ sub));
return MinCost[mask];
}The main part of the program. Set MinCost[mask] = -1 for all masks whose shipping cost for the corresponding set of items has not yet been computed.
memset(MinCost,0xFF,sizeof(MinCost));Read the input data.
scanf("%d %d",&n,&p);
for(i = 0; i < n; i++) scanf("%d",&m[i]);If the cost of a certain subset of items does not exceed (specifically, not more, not less, since the case p = 1000 is possible), then the special offer cannot be applied to their shipment. For such subsets, MinCost[mask] can be immediately computed as the sum of the costs of all items. If the sum of item costs is exactly , then we assign MinCost[mask] = p.
Thus, we preliminarily fill in the known minimum costs for small subsets. This increases the efficiency of the program.
for (mask = 0; mask < (1 << n); mask++)
{
for(Cost = i = 0; i < n; i++)
if (mask & (1 << i)) Cost += m[i];
if (Cost == 1000) Cost = p;
if (Cost <= 1000) MinCost[mask] = Cost;
}Print the answer. The entire set of items is represented by the mask 2^n - 1, whose binary representation consists of ones.
printf("%u\n",FindCost((1 << n) - 1));